Skip to content

Commit 2045852

Browse files
authored
NETOBSERV-306 : Enable ipv6 support (#24)
* Enable ipv6 support * Add space in union declaration * Add source to IPv6 type * Re-structured the ringbuffer datastructure due to bugs with union * Correct formatting errors * ebpf go modules for the v6 support Co-authored-by: Pravein <Pravein Govindan Kannan>
1 parent 1c124c0 commit 2045852

File tree

8 files changed

+154
-22
lines changed

8 files changed

+154
-22
lines changed

bpf/flow.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@ struct data_link {
1717
} __attribute__((packed));
1818

1919
// L3 network layer
20-
struct network {
21-
// todo: add protocol
22-
// todo: support ipv6
20+
struct v4ip {
2321
u32 src_ip;
2422
u32 dst_ip;
2523
} __attribute__((packed));
2624

25+
struct v6ip {
26+
struct in6_addr src_ip6;
27+
struct in6_addr dst_ip6;
28+
} __attribute__((packed));
29+
30+
struct network {
31+
struct v4ip v4ip;
32+
struct v6ip v6ip;
33+
} __attribute__((packed));
34+
2735
// L4 transport layer
2836
struct transport {
2937
u16 src_port;

bpf/flows.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <linux/ip.h>
2+
#include <linux/ipv6.h>
23
#include <linux/in.h>
34
#include <linux/tcp.h>
45
#include <linux/udp.h>
@@ -32,8 +33,8 @@ static inline int fill_iphdr(struct iphdr *ip, void *data_end, struct flow *flow
3233
return DISCARD;
3334
}
3435

35-
flow->network.src_ip = __bpf_ntohl(ip->saddr);
36-
flow->network.dst_ip = __bpf_ntohl(ip->daddr);
36+
flow->network.v4ip.src_ip = __bpf_ntohl(ip->saddr);
37+
flow->network.v4ip.dst_ip = __bpf_ntohl(ip->daddr);
3738
flow->transport.protocol = ip->protocol;
3839

3940
switch (ip->protocol) {
@@ -57,6 +58,36 @@ static inline int fill_iphdr(struct iphdr *ip, void *data_end, struct flow *flow
5758
return SUBMIT;
5859
}
5960

61+
// sets flow fields from IPv6 header information
62+
static inline int fill_ip6hdr(struct ipv6hdr *ip, void *data_end, struct flow *flow) {
63+
if ((void *)ip + sizeof(*ip) > data_end) {
64+
return DISCARD;
65+
}
66+
67+
flow->network.v6ip.src_ip6 = ip->saddr;
68+
flow->network.v6ip.dst_ip6 = ip->daddr;
69+
flow->transport.protocol = ip->nexthdr;
70+
71+
switch (ip->nexthdr) {
72+
case IPPROTO_TCP: {
73+
struct tcphdr *tcp = (void *)ip + sizeof(*ip);
74+
if ((void *)tcp + sizeof(*tcp) <= data_end) {
75+
flow->transport.src_port = __bpf_ntohs(tcp->source);
76+
flow->transport.dst_port = __bpf_ntohs(tcp->dest);
77+
}
78+
} break;
79+
case IPPROTO_UDP: {
80+
struct udphdr *udp = (void *)ip + sizeof(*ip);
81+
if ((void *)udp + sizeof(*udp) <= data_end) {
82+
flow->transport.src_port = __bpf_ntohs(udp->source);
83+
flow->transport.dst_port = __bpf_ntohs(udp->dest);
84+
}
85+
} break;
86+
default:
87+
break;
88+
}
89+
return SUBMIT;
90+
}
6091
// sets flow fields from Ethernet header information
6192
static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, struct flow *flow) {
6293
if ((void *)eth + sizeof(*eth) > data_end) {
@@ -69,6 +100,9 @@ static inline int fill_ethhdr(struct ethhdr *eth, void *data_end, struct flow *f
69100
if (flow->protocol == ETH_P_IP) {
70101
struct iphdr *ip = (void *)eth + sizeof(*eth);
71102
return fill_iphdr(ip, data_end, flow);
103+
} else if (flow->protocol == ETH_P_IPV6) {
104+
struct ipv6hdr *ip6 = (void *)eth + sizeof(*eth);
105+
return fill_ip6hdr(ip6, data_end, flow);
72106
}
73107
return SUBMIT;
74108
}
@@ -110,4 +144,4 @@ static inline int egress_flow_parse(struct __sk_buff *skb) {
110144
return flow_parse(skb, EGRESS);
111145
}
112146

113-
char __license[] SEC("license") = "GPL";
147+
char __license[] SEC("license") = "GPL";

examples/flowlogs-dump/server/flowlogs-dump-collector.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow"
2727
)
2828

29+
const ipv6 = 0x86DD
30+
2931
var (
3032
port = flag.Int("listen_port", 9999, "TCP port to listen for flows")
3133
)
@@ -38,6 +40,12 @@ var protocolByNumber = map[uint32]string{
3840
58: "ipv6-icmp",
3941
}
4042

43+
var ipProto = map[uint32]string{
44+
0x0800: "ipv4",
45+
0x0806: "arp",
46+
0x86DD: "ipv6",
47+
}
48+
4149
func ipIntToNetIP(ipAsInt uint32) net.IP {
4250
var bytes [4]byte
4351
bytes[0] = byte(ipAsInt & 0xFF)
@@ -63,19 +71,37 @@ func main() {
6371
}()
6472
for records := range receivedRecords {
6573
for _, record := range records.Entries {
66-
log.Printf("%v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d ends: %v\n",
67-
record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"),
68-
record.Interface,
69-
ipIntToNetIP(record.Network.GetSrcAddr().GetIpv4()).String(),
70-
record.Transport.SrcPort,
71-
ipIntToNetIP(record.Network.GetDstAddr().GetIpv4()).String(),
72-
record.Transport.DstPort,
73-
protocolByNumber[record.Transport.Protocol],
74-
record.Direction,
75-
record.Bytes,
76-
record.Packets,
77-
record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"),
78-
)
74+
if record.EthProtocol == ipv6 {
75+
log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d ends: %v\n",
76+
ipProto[record.EthProtocol],
77+
record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"),
78+
record.Interface,
79+
net.IP(record.Network.GetSrcAddr().GetIpv6()).To16(),
80+
record.Transport.SrcPort,
81+
net.IP(record.Network.GetDstAddr().GetIpv6()).To16(),
82+
record.Transport.DstPort,
83+
protocolByNumber[record.Transport.Protocol],
84+
record.Direction,
85+
record.Bytes,
86+
record.Packets,
87+
record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"),
88+
)
89+
} else {
90+
log.Printf("%s: %v %s IP %s:%d > %s:%d: protocol:%s dir:%d bytes:%d packets:%d ends: %v\n",
91+
ipProto[record.EthProtocol],
92+
record.TimeFlowStart.AsTime().Local().Format("15:04:05.000000"),
93+
record.Interface,
94+
ipIntToNetIP(record.Network.GetSrcAddr().GetIpv4()).String(),
95+
record.Transport.SrcPort,
96+
ipIntToNetIP(record.Network.GetDstAddr().GetIpv4()).String(),
97+
record.Transport.DstPort,
98+
protocolByNumber[record.Transport.Protocol],
99+
record.Direction,
100+
record.Bytes,
101+
record.Packets,
102+
record.TimeFlowEnd.AsTime().Local().Format("15:04:05.000000"),
103+
)
104+
}
79105
}
80106
}
81107
}

pkg/ebpf/bpf_bpfeb.o

-656 Bytes
Binary file not shown.

pkg/ebpf/bpf_bpfel.o

-1.03 KB
Binary file not shown.

pkg/exporter/grpc_proto.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,14 @@ func (g *GRPCProto) ExportFlows(input <-chan []*flow.Record) {
5454
}
5555
}
5656

57-
func flowToPB(fr *flow.Record) *pbflow.Record {
57+
func v4FlowToPB(fr *flow.Record) *pbflow.Record {
5858
return &pbflow.Record{
5959
EthProtocol: uint32(fr.Protocol),
6060
Direction: pbflow.Direction(fr.Direction),
6161
DataLink: &pbflow.DataLink{
6262
SrcMac: macToUint64(&fr.DataLink.SrcMac),
6363
DstMac: macToUint64(&fr.DataLink.DstMac),
6464
},
65-
// TODO: change this when se support IPV6 addresses
6665
Network: &pbflow.Network{
6766
SrcAddr: &pbflow.IP{IpFamily: &pbflow.IP_Ipv4{Ipv4: uint32(fr.Network.SrcAddr)}},
6867
DstAddr: &pbflow.IP{IpFamily: &pbflow.IP_Ipv4{Ipv4: uint32(fr.Network.DstAddr)}},
@@ -86,6 +85,54 @@ func flowToPB(fr *flow.Record) *pbflow.Record {
8685
}
8786
}
8887

88+
func v6FlowToPB(fr *flow.Record) *pbflow.Record {
89+
return &pbflow.Record{
90+
EthProtocol: uint32(fr.Protocol),
91+
Direction: pbflow.Direction(fr.Direction),
92+
DataLink: &pbflow.DataLink{
93+
SrcMac: macToUint64(&fr.DataLink.SrcMac),
94+
DstMac: macToUint64(&fr.DataLink.DstMac),
95+
},
96+
Network: &pbflow.Network{
97+
SrcAddr: &pbflow.IP{IpFamily: &pbflow.IP_Ipv6{Ipv6: []byte{fr.NetworkV6.SrcAddr[0],
98+
fr.NetworkV6.SrcAddr[1], fr.NetworkV6.SrcAddr[2], fr.NetworkV6.SrcAddr[3],
99+
fr.NetworkV6.SrcAddr[4], fr.NetworkV6.SrcAddr[5], fr.NetworkV6.SrcAddr[6],
100+
fr.NetworkV6.SrcAddr[7], fr.NetworkV6.SrcAddr[8], fr.NetworkV6.SrcAddr[9],
101+
fr.NetworkV6.SrcAddr[10], fr.NetworkV6.SrcAddr[11], fr.NetworkV6.SrcAddr[12],
102+
fr.NetworkV6.SrcAddr[13], fr.NetworkV6.SrcAddr[14], fr.NetworkV6.SrcAddr[15]}}},
103+
DstAddr: &pbflow.IP{IpFamily: &pbflow.IP_Ipv6{Ipv6: []byte{fr.NetworkV6.DstAddr[0],
104+
fr.NetworkV6.DstAddr[1], fr.NetworkV6.DstAddr[2], fr.NetworkV6.DstAddr[3],
105+
fr.NetworkV6.DstAddr[4], fr.NetworkV6.DstAddr[5], fr.NetworkV6.DstAddr[6],
106+
fr.NetworkV6.DstAddr[7], fr.NetworkV6.DstAddr[8], fr.NetworkV6.DstAddr[9],
107+
fr.NetworkV6.DstAddr[10], fr.NetworkV6.DstAddr[11], fr.NetworkV6.DstAddr[12],
108+
fr.NetworkV6.DstAddr[13], fr.NetworkV6.DstAddr[14], fr.NetworkV6.DstAddr[15]}}},
109+
},
110+
Transport: &pbflow.Transport{
111+
Protocol: uint32(fr.Transport.Protocol),
112+
SrcPort: uint32(fr.Transport.SrcPort),
113+
DstPort: uint32(fr.Transport.DstPort),
114+
},
115+
Bytes: uint64(fr.Bytes),
116+
TimeFlowStart: &timestamppb.Timestamp{
117+
Seconds: fr.TimeFlowStart.Unix(),
118+
Nanos: int32(fr.TimeFlowStart.Nanosecond()),
119+
},
120+
TimeFlowEnd: &timestamppb.Timestamp{
121+
Seconds: fr.TimeFlowEnd.Unix(),
122+
Nanos: int32(fr.TimeFlowEnd.Nanosecond()),
123+
},
124+
Packets: uint64(fr.Packets),
125+
Interface: fr.Interface,
126+
}
127+
}
128+
129+
func flowToPB(fr *flow.Record) *pbflow.Record {
130+
if fr.Protocol == flow.IPv6Type {
131+
return v6FlowToPB(fr)
132+
}
133+
return v4FlowToPB(fr)
134+
}
135+
89136
// Mac bytes are encoded in the same order as in the array. This is, a Mac
90137
// like 11:22:33:44:55:66 will be encoded as 0x112233445566
91138
func macToUint64(m *flow.MacAddr) uint64 {

pkg/flow/record.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ import (
1010
)
1111

1212
const MacLen = 6
13+
const IP6Len = 16
14+
const IPv6Type = 0x86DD
15+
16+
// IPv6Type value as defined in IEEE 802: https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
1317

14-
// TODO: support IPv6
1518
type RawIP uint32
1619
type HumanBytes uint64
1720
type MacAddr [MacLen]uint8
1821
type Direction uint8
1922
type TransportProtocol uint8
23+
type IP6Addr [IP6Len]uint8
2024

2125
type DataLink struct {
2226
SrcMac MacAddr
@@ -28,6 +32,11 @@ type Network struct {
2832
DstAddr RawIP
2933
}
3034

35+
type NetworkV6 struct {
36+
SrcAddr IP6Addr
37+
DstAddr IP6Addr
38+
}
39+
3140
type Transport struct {
3241
SrcPort uint16
3342
DstPort uint16
@@ -40,6 +49,7 @@ type key struct {
4049
Direction Direction
4150
DataLink DataLink
4251
Network Network
52+
NetworkV6 NetworkV6
4353
Transport Transport
4454
// TODO: add TOS field
4555
}

pkg/flow/record_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func TestRecordBinaryEncoding(t *testing.T) {
1818
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // data_link: u8[6] dst_mac
1919
0x06, 0x07, 0x08, 0x09, // network: u32 src_ip
2020
0x0a, 0x0b, 0x0c, 0x0d, // network: u32 dst_ip
21+
0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09, // network6: u8[16] src_ip
22+
0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d, // network6: u8[16] dst_ip
2123
0x0e, 0x0f, // transport: u16 src_port
2224
0x10, 0x11, // transport: u16 dst_port
2325
0x12, // transport: u8protocol
@@ -38,6 +40,10 @@ func TestRecordBinaryEncoding(t *testing.T) {
3840
SrcAddr: 0x09080706,
3941
DstAddr: 0x0d0c0b0a,
4042
},
43+
NetworkV6: NetworkV6{
44+
SrcAddr: IP6Addr{0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09, 0x06, 0x07, 0x08, 0x09},
45+
DstAddr: IP6Addr{0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d, 0x0a, 0x0b, 0x0c, 0x0d},
46+
},
4147
Transport: Transport{
4248
SrcPort: 0x0f0e,
4349
DstPort: 0x1110,
@@ -47,4 +53,5 @@ func TestRecordBinaryEncoding(t *testing.T) {
4753
Bytes: 0x1a19181716151413,
4854
},
4955
}, *fr)
56+
5057
}

0 commit comments

Comments
 (0)