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

View File

@ -158,14 +158,11 @@ table ip filter {
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"
counter inputc {
packets 23 bytes 42
}
}
table ip6 filter {
counter fwded {
counter outputc {
packets 23 bytes 42
}
@ -174,6 +171,45 @@ table ip6 filter {
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"
}
}
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{}
func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj {
objs, err := c.GetObj(o)
obj, err := c.GetObject(o)
if err != nil {
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
{
// 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 {
if co, ok := obj.(*nftables.CounterObj); ok {
return co
}
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()