Skip to content

Commit 03711aa

Browse files
committed
Support IPv6 for egress metrics
Signed-off-by: terashima <tomoya-terashima@cybozu.co.jp>
1 parent ea2ce3d commit 03711aa

File tree

2 files changed

+79
-33
lines changed

2 files changed

+79
-33
lines changed

v2/cmd/coil-egress/sub/run.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,26 @@ func subMain() error {
6363
return errors.New(constants.EnvAddresses + " environment variable must be set")
6464
}
6565
var ipv4, ipv6 net.IP
66+
protocolMap := make(map[string]struct{})
6667
for _, addr := range myAddresses {
6768
n := net.ParseIP(addr)
6869
if n == nil {
6970
return errors.New(constants.EnvAddresses + "contains invalid address: " + addr)
7071
}
7172
if n4 := n.To4(); n4 != nil {
7273
ipv4 = n4
74+
protocolMap["ipv4"] = struct{}{}
7375
} else {
7476
ipv6 = n
77+
protocolMap["ipv6"] = struct{}{}
7578
}
7679
}
7780

81+
protocols := make([]string, 0, 0)
82+
for protocol, _ := range protocolMap {
83+
protocols = append(protocols, protocol)
84+
}
85+
7886
setupLog.Info("detected local IP addresses", "ipv4", ipv4.String(), "ipv6", ipv6.String())
7987

8088
timeout := gracefulTimeout
@@ -117,7 +125,7 @@ func subMain() error {
117125

118126
setupLog.Info("setup egress metrics collector")
119127
runner := egressMetrics.NewRunner()
120-
egressCollector, err := egressMetrics.NewEgressCollector(myNS, os.Getenv("HOSTNAME"), myName)
128+
egressCollector, err := egressMetrics.NewEgressCollector(myNS, os.Getenv("HOSTNAME"), myName, protocols)
121129
if err != nil {
122130
return err
123131
}

v2/pkg/metrics/egress.go

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package metrics
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"os"
78
"strconv"
89
"strings"
@@ -24,55 +25,68 @@ var (
2425
Subsystem: "egress",
2526
Name: "nf_conntrack_entries_count",
2627
Help: "the number of entries in the nf_conntrack table",
27-
}, []string{"namespace", "pod", "egress"})
28+
}, []string{"namespace", "pod", "egress", "protocol"})
2829

2930
NfConnctackLimit = prometheus.NewGaugeVec(prometheus.GaugeOpts{
3031
Namespace: constants.MetricsNS,
3132
Subsystem: "egress",
3233
Name: "nf_conntrack_entries_limit",
3334
Help: "the limit of the nf_conntrack table",
34-
}, []string{"namespace", "pod", "egress"})
35+
}, []string{"namespace", "pod", "egress", "protocol"})
3536

3637
NfTableMasqueradePackets = prometheus.NewGaugeVec(prometheus.GaugeOpts{
3738
Namespace: constants.MetricsNS,
3839
Subsystem: "egress",
3940
Name: "nftables_masqueraded_packets_total",
4041
Help: "the number of packets that are masqueraded by nftables",
41-
}, []string{"namespace", "pod", "egress"})
42+
}, []string{"namespace", "pod", "egress", "protocol"})
4243

4344
NfTableMasqueradeBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
4445
Namespace: constants.MetricsNS,
4546
Subsystem: "egress",
4647
Name: "nftables_masqueraded_bytes_total",
4748
Help: "the number of bytes that are masqueraded by nftables",
48-
}, []string{"namespace", "pod", "egress"})
49+
}, []string{"namespace", "pod", "egress", "protocol"})
4950

5051
NfTableInvalidPackets = prometheus.NewGaugeVec(prometheus.GaugeOpts{
5152
Namespace: constants.MetricsNS,
5253
Subsystem: "egress",
5354
Name: "nftables_invalid_packets_total",
5455
Help: "the number of packets that are dropped as invalid packets by nftables",
55-
}, []string{"namespace", "pod", "egress"})
56+
}, []string{"namespace", "pod", "egress", "protocol"})
5657

5758
NfTableInvalidBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
5859
Namespace: constants.MetricsNS,
5960
Subsystem: "egress",
6061
Name: "nftables_invalid_bytes_total",
6162
Help: "the number of bytes that are dropped as invalid packets by nftables",
62-
}, []string{"namespace", "pod", "egress"})
63+
}, []string{"namespace", "pod", "egress", "protocol"})
6364
)
6465

6566
type egressCollector struct {
66-
conn *nftables.Conn
67-
nfConnctackCount prometheus.Gauge
68-
nfConnctackLimit prometheus.Gauge
67+
conn *nftables.Conn
68+
nfConnctackCount prometheus.Gauge
69+
nfConnctackLimit prometheus.Gauge
70+
perProtocol map[string]*nfTablesPerProtocolMetrics
71+
}
72+
73+
type nfTablesPerProtocolMetrics struct {
6974
nfTablesNATPackets prometheus.Gauge
7075
nfTablesNATBytes prometheus.Gauge
7176
nfTablesInvalidPackets prometheus.Gauge
7277
nfTablesInvalidBytes prometheus.Gauge
7378
}
7479

75-
func NewEgressCollector(ns, pod, egress string) (Collector, error) {
80+
func newNfTablesPerProtocolMetrics(ns, pod, egress, protocol string) *nfTablesPerProtocolMetrics {
81+
return &nfTablesPerProtocolMetrics{
82+
nfTablesNATPackets: NfTableMasqueradePackets.WithLabelValues(ns, pod, egress, protocol),
83+
nfTablesNATBytes: NfTableMasqueradeBytes.WithLabelValues(ns, pod, egress, protocol),
84+
nfTablesInvalidPackets: NfTableInvalidPackets.WithLabelValues(ns, pod, egress, protocol),
85+
nfTablesInvalidBytes: NfTableInvalidBytes.WithLabelValues(ns, pod, egress, protocol),
86+
}
87+
}
88+
89+
func NewEgressCollector(ns, pod, egress string, protocols []string) (Collector, error) {
7690
NfConnctackCount.Reset()
7791
NfConnctackLimit.Reset()
7892
NfTableMasqueradeBytes.Reset()
@@ -85,14 +99,16 @@ func NewEgressCollector(ns, pod, egress string) (Collector, error) {
8599
return nil, err
86100
}
87101

102+
perProtocols := make(map[string]*nfTablesPerProtocolMetrics)
103+
for _, protocol := range protocols {
104+
perProtocols[protocol] = newNfTablesPerProtocolMetrics(ns, pod, egress, protocol)
105+
}
106+
88107
return &egressCollector{
89-
conn: c,
90-
nfConnctackCount: NfConnctackCount.WithLabelValues(ns, pod, egress),
91-
nfConnctackLimit: NfConnctackLimit.WithLabelValues(ns, pod, egress),
92-
nfTablesNATPackets: NfTableMasqueradePackets.WithLabelValues(ns, pod, egress),
93-
nfTablesNATBytes: NfTableMasqueradeBytes.WithLabelValues(ns, pod, egress),
94-
nfTablesInvalidPackets: NfTableInvalidPackets.WithLabelValues(ns, pod, egress),
95-
nfTablesInvalidBytes: NfTableInvalidBytes.WithLabelValues(ns, pod, egress),
108+
conn: c,
109+
nfConnctackCount: NfConnctackCount.WithLabelValues(ns, pod, egress),
110+
nfConnctackLimit: NfConnctackLimit.WithLabelValues(ns, pod, egress),
111+
perProtocol: perProtocols,
96112
}, nil
97113
}
98114

@@ -114,25 +130,32 @@ func (c *egressCollector) Update(ctx context.Context) error {
114130
}
115131
c.nfConnctackLimit.Set(float64(val))
116132

117-
natPackets, natBytes, err := c.getNfTablesNATCounter()
118-
if err != nil {
119-
return err
120-
}
121-
c.nfTablesNATPackets.Set(float64(natPackets))
122-
c.nfTablesNATBytes.Set(float64(natBytes))
133+
for protocol, nfTablesMetrics := range c.perProtocol {
134+
natPackets, natBytes, err := c.getNfTablesNATCounter(protocol)
135+
if err != nil {
136+
return err
137+
}
138+
nfTablesMetrics.nfTablesNATPackets.Set(float64(natPackets))
139+
nfTablesMetrics.nfTablesNATBytes.Set(float64(natBytes))
140+
141+
invalidPackets, invalidBytes, err := c.getNfTablesInvalidCounter(protocol)
142+
if err != nil {
143+
return err
144+
}
145+
nfTablesMetrics.nfTablesInvalidPackets.Set(float64(invalidPackets))
146+
nfTablesMetrics.nfTablesInvalidBytes.Set(float64(invalidBytes))
123147

124-
invalidPackets, invalidBytes, err := c.getNfTablesInvalidCounter()
125-
if err != nil {
126-
return err
127148
}
128-
c.nfTablesInvalidPackets.Set(float64(invalidPackets))
129-
c.nfTablesInvalidBytes.Set(float64(invalidBytes))
130149

131150
return nil
132151
}
133152

134-
func (c *egressCollector) getNfTablesNATCounter() (uint64, uint64, error) {
135-
table := &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "nat"}
153+
func (c *egressCollector) getNfTablesNATCounter(protocol string) (uint64, uint64, error) {
154+
family, err := stringToTableFamily(protocol)
155+
if err != nil {
156+
return 0, 0, err
157+
}
158+
table := &nftables.Table{Family: family, Name: "nat"}
136159
rules, err := c.conn.GetRules(table, &nftables.Chain{
137160
Name: "POSTROUTING",
138161
Type: nftables.ChainTypeNAT,
@@ -153,8 +176,12 @@ func (c *egressCollector) getNfTablesNATCounter() (uint64, uint64, error) {
153176
return 0, 0, errors.New("a masquerade rule is not found")
154177
}
155178

156-
func (c *egressCollector) getNfTablesInvalidCounter() (uint64, uint64, error) {
157-
table := &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"}
179+
func (c *egressCollector) getNfTablesInvalidCounter(protocol string) (uint64, uint64, error) {
180+
family, err := stringToTableFamily(protocol)
181+
if err != nil {
182+
return 0, 0, err
183+
}
184+
table := &nftables.Table{Family: family, Name: "filter"}
158185
rules, err := c.conn.GetRules(table, &nftables.Chain{
159186
Name: "FORWARD",
160187
Type: nftables.ChainTypeFilter,
@@ -186,3 +213,14 @@ func readUintFromFile(path string) (uint64, error) {
186213
}
187214
return val, nil
188215
}
216+
217+
func stringToTableFamily(protocol string) (nftables.TableFamily, error) {
218+
switch strings.ToLower(protocol) {
219+
case "ipv4":
220+
return nftables.TableFamilyIPv4, nil
221+
case "ipv6":
222+
return nftables.TableFamilyIPv6, nil
223+
default:
224+
return nftables.TableFamilyUnspecified, fmt.Errorf("unsupported family type: %s", protocol)
225+
}
226+
}

0 commit comments

Comments
 (0)