From 593cd8c12defe185725a1a7bbe8689f93faddc87 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 8 Mar 2022 22:47:18 +0100 Subject: [PATCH] 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 --- cmd/netconfigd/netconfigd.go | 41 +++++++++---- integration/netconfig/netconfig_test.go | 50 +++++++++++++--- internal/netconfig/netconfig.go | 76 +++++++++++++++++-------- 3 files changed, 124 insertions(+), 43 deletions(-) diff --git a/cmd/netconfigd/netconfigd.go b/cmd/netconfigd/netconfigd.go index fbffd31..d9f9fbd 100644 --- a/cmd/netconfigd/netconfigd.go +++ b/cmd/netconfigd/netconfigd.go @@ -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 } diff --git a/integration/netconfig/netconfig_test.go b/integration/netconfig/netconfig_test.go index 9237360..7e8ac40 100644 --- a/integration/netconfig/netconfig_test.go +++ b/integration/netconfig/netconfig_test.go @@ -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" + } }` } diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index f13fd01..0b250f1 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -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()