export input/output nftables counters as well as forwarded

Thus far, we have only had forwarded bytes metrics.

Notably, forwarded bytes does not include bytes that were sent by the router
itself, e.g. by the webserver or rsync server running on the machine.

fixes https://github.com/rtr7/router7/issues/71
This commit is contained in:
Michael Stapelberg 2022-03-08 22:47:18 +01:00
parent 8dc93c66c4
commit 593cd8c12d
3 changed files with 124 additions and 43 deletions

View File

@ -44,6 +44,8 @@ var (
func init() { func init() {
var c nftables.Conn var c nftables.Conn
filter4 := &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"}
filter6 := &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"}
for _, metric := range []struct { for _, metric := range []struct {
name string name string
labels prometheus.Labels labels prometheus.Labels
@ -53,18 +55,34 @@ func init() {
{ {
name: "filter_forward", name: "filter_forward",
labels: prometheus.Labels{"family": "ipv4"}, labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{ obj: &nftables.CounterObj{Table: filter4, Name: "fwded"},
Table: &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"},
Name: "fwded",
},
}, },
{ {
name: "filter_forward", name: "filter_forward",
labels: prometheus.Labels{"family": "ipv6"}, labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{ obj: &nftables.CounterObj{Table: filter6, Name: "fwded"},
Table: &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"},
Name: "fwded",
}, },
{
name: "filter_input",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{Table: filter4, Name: "inputc"},
},
{
name: "filter_input",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{Table: filter6, Name: "inputc"},
},
{
name: "filter_output",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{Table: filter4, Name: "outputc"},
},
{
name: "filter_output",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{Table: filter6, Name: "outputc"},
}, },
} { } {
metric := metric // copy metric := metric // copy
@ -72,12 +90,11 @@ func init() {
updateCounter := func() { updateCounter := func() {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
objs, err := c.GetObjReset(metric.obj) obj, err := c.ResetObject(metric.obj)
if err != nil || if err != nil {
len(objs) != 1 {
return return
} }
if co, ok := objs[0].(*nftables.CounterObj); ok { if co, ok := obj.(*nftables.CounterObj); ok {
metric.packets += co.Packets metric.packets += co.Packets
metric.bytes += co.Bytes metric.bytes += co.Bytes
} }

View File

@ -158,14 +158,11 @@ table ip filter {
packets 23 bytes 42 packets 23 bytes 42
} }
chain forward { counter inputc {
type filter hook forward priority 0; policy accept; packets 23 bytes 42
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded"
} }
}
table ip6 filter { counter outputc {
counter fwded {
packets 23 bytes 42 packets 23 bytes 42
} }
@ -174,6 +171,45 @@ table ip6 filter {
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded" counter name "fwded"
} }
chain input {
type filter hook input priority 0; policy accept;
counter name "inputc"
}
chain output {
type filter hook output priority 0; policy accept;
counter name "outputc"
}
}
table ip6 filter {
counter fwded {
packets 23 bytes 42
}
counter inputc {
packets 23 bytes 42
}
counter outputc {
packets 23 bytes 42
}
chain forward {
type filter hook forward priority 0; policy accept;
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded"
}
chain input {
type filter hook input priority 0; policy accept;
counter name "inputc"
}
chain output {
type filter hook output priority 0; policy accept;
counter name "outputc"
}
}` }`
} }

View File

@ -648,35 +648,13 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta
var DefaultCounterObj = &nftables.CounterObj{} var DefaultCounterObj = &nftables.CounterObj{}
func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj { func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj {
objs, err := c.GetObj(o) obj, err := c.GetObject(o)
if err != nil { if err != nil {
o.Bytes = DefaultCounterObj.Bytes o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets o.Packets = DefaultCounterObj.Packets
return o return o
} }
{ if co, ok := obj.(*nftables.CounterObj); ok {
// TODO: remove this workaround once travis has workers with a newer kernel
// than its current Ubuntu trusty kernel (Linux 4.4.0):
var filtered []nftables.Obj
for _, obj := range objs {
co, ok := obj.(*nftables.CounterObj)
if !ok {
continue
}
if co.Table.Name != o.Table.Name {
continue
}
filtered = append(filtered, obj)
}
objs = filtered
}
if got, want := len(objs), 1; got != want {
log.Printf("could not carry counter values: unexpected number of objects in table %v: got %d, want %d", o.Table.Name, got, want)
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
if co, ok := objs[0].(*nftables.CounterObj); ok {
return co return co
} }
o.Bytes = DefaultCounterObj.Bytes o.Bytes = DefaultCounterObj.Bytes
@ -888,6 +866,56 @@ func applyFirewall(dir, ifname string) error {
}, },
}, },
}) })
input := c.AddChain(&nftables.Chain{
Name: "input",
Hooknum: nftables.ChainHookInput,
Priority: nftables.ChainPriorityFilter,
Table: filter,
Type: nftables.ChainTypeFilter,
})
counterObj = getCounterObj(c, &nftables.CounterObj{
Table: filter,
Name: "inputc",
})
counter = c.AddObj(counterObj).(*nftables.CounterObj)
c.AddRule(&nftables.Rule{
Table: filter,
Chain: input,
Exprs: []expr.Any{
// [ counter name input ]
&expr.Objref{
Type: NFT_OBJECT_COUNTER,
Name: counter.Name,
},
},
})
output := c.AddChain(&nftables.Chain{
Name: "output",
Hooknum: nftables.ChainHookOutput,
Priority: nftables.ChainPriorityFilter,
Table: filter,
Type: nftables.ChainTypeFilter,
})
counterObj = getCounterObj(c, &nftables.CounterObj{
Table: filter,
Name: "outputc",
})
counter = c.AddObj(counterObj).(*nftables.CounterObj)
c.AddRule(&nftables.Rule{
Table: filter,
Chain: output,
Exprs: []expr.Any{
// [ counter name output ]
&expr.Objref{
Type: NFT_OBJECT_COUNTER,
Name: counter.Name,
},
},
})
} }
return c.Flush() return c.Flush()