Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge I/O statistics counters for Tap/RawSocket apps into next #962

Merged
merged 18 commits into from
Jul 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/apps/intel/intel_app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function Intel82599:new (arg)
counter.set(self.stats.counters.type, 0x1000) -- Hardware interface
counter.set(self.stats.counters.dtime, C.get_unix_time())
counter.set(self.stats.counters.mtu, self.dev.mtu)
counter.set(self.stats.counters.speed, 10000000) -- 10 Gbits
counter.set(self.stats.counters.speed, 10000000000) -- 10 Gbits
counter.set(self.stats.counters.status, 2) -- down
if not conf.vmdq and conf.macaddr then
counter.set(self.stats.counters.macaddr,
Expand Down
44 changes: 44 additions & 0 deletions src/apps/ipsec/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# IPsec Apps

## AES128gcm (apps.ipsec.esp)

The `AES128gcm` implements an ESP transport tunnel using the AES-GCM-128
cipher. It encrypts packets received on its `decapsulated` port and transmits
them on its `encapsulated` port, and vice-versa. Packets arriving on the
`decapsulated` port must have an IPv6 header, and packets arriving on the
`encapsulated` port must have an IPv6 header followed by an ESP header,
otherwise they will be discarded.

References:

- `lib.ipsec.esp`

DIAGRAM: AES128gcm
+-----------+
encapsulated | |
---->* AES128gcm *<----
<----* *---->
| | decapsulated
+-----------+

encapsulated
--------\ /----------
<-------|---/ /------->
\-----/ decapsulated

### Configuration

The `AES128gcm` app accepts a table as its configuration argument. The
following keys are defined:

— Key **spi**

*Required*. Security Parameter Index. A 32 bit integer.

— Key **key**

*Required*. 20 bytes in form of a hex encoded string.

— Key **replay_window**

*Optional*. Size of the “Anti-Replay Window”. Defaults to 128.
70 changes: 70 additions & 0 deletions src/apps/ipsec/esp.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
-- Use of this source code is governed by the Apache 2.0 license; see COPYING.

-- This app implements a point-to-point encryption tunnel using ESP with
-- AES-128-GCM.

module(..., package.seeall)
local esp = require("lib.ipsec.esp")
local counter = require("core.counter")
local C = require("ffi").C

AES128gcm = {}

local provided_counters = {
'type', 'dtime', 'txerrors', 'rxerrors'
}

function AES128gcm:new (arg)
local conf = arg and config.parse_app_arg(arg) or {}
local self = {}
self.encrypt = esp.esp_v6_encrypt:new{
mode = "aes-128-gcm",
spi = conf.spi,
keymat = conf.key:sub(1, 32),
salt = conf.key:sub(33, 40)}
self.decrypt = esp.esp_v6_decrypt:new{
mode = "aes-128-gcm",
spi = conf.spi,
keymat = conf.key:sub(1, 32),
salt = conf.key:sub(33, 40),
window_size = conf.replay_window}
self.counters = {}
for _, name in ipairs(provided_counters) do
self.counters[name] = counter.open(name)
end
counter.set(self.counters.type, 0x1001) -- Virtual interface
counter.set(self.counters.dtime, C.get_unix_time())
return setmetatable(self, {__index = AES128gcm})
end

function AES128gcm:push ()
-- Encapsulation path
local input = self.input.decapsulated
local output = self.output.encapsulated
for _=1,link.nreadable(input) do
local p = link.receive(input)
if self.encrypt:encapsulate(p) then
link.transmit(output, p)
else
packet.free(p)
counter.add(self.counters.txerrors)
end
end
-- Decapsulation path
local input = self.input.encapsulated
local output = self.output.decapsulated
for _=1,link.nreadable(input) do
local p = link.receive(input)
if self.decrypt:decapsulate(p) then
link.transmit(output, p)
else
packet.free(p)
counter.add(self.counters.rxerrors)
end
end
end

function AES128gcm:stop ()
-- delete counters
for name, _ in pairs(self.counters) do counter.delete(name) end
end
47 changes: 47 additions & 0 deletions src/apps/ipv6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ milliseconds. Default is 1,000ms.
*Optional*. Number of neighbor solicitation retransmissions. Default is
unlimited retransmissions.

### Special Counters

— Key **ns_checksum_errors**

Neighbor solicitation requests dropped due to invalid ICMP checksum.

— Key **ns_target_address_errors**

Neighbor solicitation requests dropped due to invalid target address.

— Key **na_duplicate_errors**

Neighbor advertisement requests dropped because next-hop is already resolved.

— Key **na_target_address_errors**

Neighbor advertisement requests dropped due to invalid target address.

— Key **nd_protocol_errors**

Neighbor discovery requests dropped due to protocol errors (invalid IPv6
hop-limit or invalid neighbor solicitation request options).


## SimpleKeyedTunnel (apps.keyed_ipv6_tunnel.tunnel)

The `SimpleKeyedTunnel` app implements "a simple L2 Ethernet over IPv6
Expand Down Expand Up @@ -115,3 +139,26 @@ the L2TPv3 header will be overwritten with this value.

*Optional*. Destination MAC as a string. Not required if overwritten by
an app such as `nd_light`.


### Special Counters

— Key **length_errors**

Ingress packets dropped due to invalid length (packet too short).

— Key **protocol_errors**

Ingress packets dropped due to unrecognized IPv6 protocol ID.

— Key **cookie_errors**

Ingress packets dropped due to wrong cookie value.

— Key **remote_address_errors**

Ingress packets dropped due to wrong remote IPv6 endpoint address.

— Key **local_address_errors**

Ingress packets dropped due to wrong local IPv6 endpoint address.
40 changes: 38 additions & 2 deletions src/apps/ipv6/nd_light.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ local app = require("core.app")
local link = require("core.link")
local config = require("core.config")
local packet = require("core.packet")
local counter = require("core.counter")
local datagram = require("lib.protocol.datagram")
local ethernet = require("lib.protocol.ethernet")
local ipv6 = require("lib.protocol.ipv6")
Expand Down Expand Up @@ -78,6 +79,13 @@ local function check_ip_address(ip, desc)
return ip
end

local provided_counters = {
'type', 'dtime', 'status', 'rxerrors', 'txerrors', 'txdrop',
'ns_checksum_errors', 'ns_target_address_errors',
'na_duplicate_errors', 'na_target_address_errors',
'nd_protocol_errors'
}

function nd_light:new (arg)
local arg = arg and config.parse_app_arg(arg) or {}
--copy the args to avoid changing the arg table so that it stays reusable.
Expand Down Expand Up @@ -201,6 +209,16 @@ function nd_light:new (arg)
mem = ffi.new("uint8_t *[1]")
}
o._logger = lib.logger_new({ module = 'nd_light' })

-- Create counters
o.counters = {}
for _, name in ipairs(provided_counters) do
o.counters[name] = counter.open(name)
end
counter.set(o.counters.type, 0x1001) -- Virtual interface
counter.set(o.counters.dtime, C.get_unix_time())
counter.set(o.counters.status, 2) -- Link down

return o
end

Expand All @@ -209,13 +227,16 @@ local function ns (self, dgram, eth, ipv6, icmp)
local mem, length = self._cache.mem
mem[0], length = dgram:payload()
if not icmp:checksum_check(mem[0], length, ipv6) then
self._logger:log("bad icmp checksum")
counter.add(self.counters.ns_checksum_errors)
counter.add(self.counters.rxerrors)
return nil
end
-- Parse the neighbor solicitation and check if it contains our own
-- address as target
local ns = dgram:parse_match(nil, self._match_ns)
if not ns then
counter.add(self.counters.ns_target_address_errors)
counter.add(self.counters.rxerrors)
return nil
end
-- Ignore options as long as we don't implement a proper neighbor
Expand All @@ -236,22 +257,29 @@ end
-- Process neighbor advertisement
local function na (self, dgram, eth, ipv6, icmp)
if self._eth_header then
counter.add(self.counters.na_duplicate_errors)
counter.add(self.counters.rxerrors)
return nil
end
local na = dgram:parse_match(nil, self._match_na)
if not na then
counter.add(self.counters.na_target_address_errors)
counter.add(self.counters.rxerrors)
return nil
end
local option = na:options(dgram:payload())
if not (#option == 1 and option[1]:type() == 2) then
-- Invalid NS, ignore
counter.add(self.counters.nd_protocol_errors)
counter.add(self.counters.rxerrors)
return nil
end
self._eth_header = ethernet:new({ src = self._config.local_mac,
dst = option[1]:option():addr(),
type = 0x86dd })
self._logger:log(string.format("Resolved next-hop %s to %s", ipv6:ntop(self._config.next_hop),
ethernet:ntop(option[1]:option():addr())))
counter.set(self.counters.status, 1) -- Link up
return nil
end

Expand All @@ -265,6 +293,8 @@ local function from_south (self, p)
local eth, ipv6, icmp = unpack(dgram:stack())
if ipv6:hop_limit() ~= 255 then
-- Avoid off-link spoofing as per RFC
counter.add(self.counters.nd_protocol_errors)
counter.add(self.counters.rxerrors)
return nil
end
local result
Expand Down Expand Up @@ -311,13 +341,17 @@ function nd_light:push ()
-- Drop packets until ND for the next-hop
-- has completed.
packet.free(link.receive(l_in))
counter.add(self.counters.txdrop)
else
local p = cache.p
p[0] = link.receive(l_in)
if p[0].length >= self._eth_header:sizeof() then
self._eth_header:copy(p[0].data)
link.transmit(l_out, p[0])
else packet.free(p[0]) end
else
packet.free(p[0])
counter.add(self.counters.txerrors)
end
end
end
end
Expand All @@ -328,6 +362,8 @@ function nd_light:stop ()
self._next_hop.packet = nil
packet.free(self._sna.packet)
self._sna.packet = nil
-- delete counters
for name, _ in pairs(self.counters) do counter.delete(name) end
end

function selftest ()
Expand Down
Loading