Skip to content

Commit 6ad14f8

Browse files
authored
Merge pull request #8790 from tomastigera/tomas-bpf-vxlan-tunnel-src-port-fix
[BPF] Variable source port for VXLAN NodePort tunnel
2 parents d07c1d9 + d5d55f9 commit 6ad14f8

File tree

7 files changed

+57
-10
lines changed

7 files changed

+57
-10
lines changed

felix/bpf-gpl/nat4.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#define VXLAN_ENCAP_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
2020
sizeof(struct udphdr) + sizeof(struct vxlanhdr))
2121

22-
static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, __be32 *ip_src, __be32 *ip_dst)
22+
static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, __be32 *ip_src, __be32 *ip_dst, __u16 src_port)
2323
{
2424
int ret;
2525
__wsum csum;
@@ -65,7 +65,8 @@ static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, __be32 *ip_src,
6565
ip_hdr(ctx)->check = 0;
6666
ip_hdr(ctx)->protocol = IPPROTO_UDP;
6767

68-
udp->source = udp->dest = bpf_htons(VXLAN_PORT);
68+
udp->source = bpf_htons(src_port);
69+
udp->dest = bpf_htons(VXLAN_PORT);
6970
udp->len = bpf_htons(bpf_ntohs(ip_hdr(ctx)->tot_len) - sizeof(struct iphdr));
7071

7172
*((__u8*)&vxlan->flags) = 1 << 3; /* set the I flag to make the VNI valid */

felix/bpf-gpl/nat6.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#define VXLAN_ENCAP_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
2020
sizeof(struct udphdr) + sizeof(struct vxlanhdr))
2121

22-
static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, ipv6_addr_t *ip_src, ipv6_addr_t *ip_dst)
22+
static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, ipv6_addr_t *ip_src, ipv6_addr_t *ip_dst, __u16 src_port)
2323
{
2424
__u32 new_hdrsz = sizeof(struct ethhdr) + sizeof(struct ipv6hdr) +
2525
sizeof(struct udphdr) + sizeof(struct vxlanhdr);
@@ -56,7 +56,8 @@ static CALI_BPF_INLINE int vxlan_encap(struct cali_tc_ctx *ctx, ipv6_addr_t *ip_
5656
ip_hdr(ctx)->payload_len = bpf_htons(bpf_ntohs(ip_hdr(ctx)->payload_len) + new_hdrsz);
5757
ip_hdr(ctx)->nexthdr = IPPROTO_UDP;
5858

59-
udp->source = udp->dest = bpf_htons(VXLAN_PORT);
59+
udp->source = bpf_htons(src_port);
60+
udp->dest = bpf_htons(VXLAN_PORT);
6061
udp->len = bpf_htons(bpf_ntohs(ip_hdr(ctx)->payload_len) - sizeof(struct iphdr));
6162
/* XXX we leave udp->check == 0 which is not legal in IPv6, but we are
6263
* the only ones parsing that packet!

felix/bpf-gpl/tc.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -1053,12 +1053,22 @@ static CALI_BPF_INLINE enum do_nat_res do_nat(struct cali_tc_ctx *ctx,
10531053
}
10541054
}
10551055

1056-
if (vxlan_encap(ctx, &STATE->ip_src, &STATE->ip_dst)) {
1056+
/* Trivial hash to use multiple vxlan flows. Note that any value will do
1057+
* as long as it is a constant for this direction of the flow. Does not
1058+
* even need to be the same for both directions.
1059+
*
1060+
* ICMP does not have ports, but there is little to no worries about a
1061+
* possible out-of-order processing in relation to the related flow.
1062+
*/
1063+
__u16 vxlan_src_port = STATE->sport ^ STATE->dport;
1064+
1065+
if (vxlan_encap(ctx, &STATE->ip_src, &STATE->ip_dst, vxlan_src_port)) {
10571066
deny_reason(ctx, CALI_REASON_ENCAP_FAIL);
10581067
goto deny;
10591068
}
10601069

1061-
STATE->sport = STATE->dport = VXLAN_PORT;
1070+
STATE->sport = vxlan_src_port;
1071+
STATE->dport = VXLAN_PORT;
10621072
STATE->ip_proto = IPPROTO_UDP;
10631073

10641074
CALI_DEBUG("vxlan return %d ifindex_fwd %d\n",

felix/bpf-gpl/ut/ipv4_opts_test.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static CALI_BPF_INLINE int calico_unittest_entry (struct __sk_buff *skb)
4747
__u32 a = 0x06060606;
4848
__u32 b = 0x10101010;
4949

50-
if (vxlan_encap(ctx, &a, &b)) {
50+
if (vxlan_encap(ctx, &a, &b, 0xdead)) {
5151
CALI_DEBUG("vxlan: encap failed!\n");
5252
deny_reason(ctx, CALI_REASON_ENCAP_FAIL);
5353
goto deny;

felix/bpf-gpl/ut/nat_encap_test.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ static CALI_BPF_INLINE int calico_unittest_entry (struct __sk_buff *skb)
3535
__u32 a = HOST_IP;
3636
__u32 b = 0x02020202;
3737

38-
return vxlan_encap(ctx, &a, &b);
38+
return vxlan_encap(ctx, &a, &b, 0xdead);
3939
}

felix/bpf/ut/nat_encap_test.go

-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ func checkVxlan(pktR gopacket.Packet) gopacket.Packet {
106106
udpL := pktR.Layer(layers.LayerTypeUDP)
107107
Expect(udpL).NotTo(BeNil())
108108
udpR := udpL.(*layers.UDP)
109-
Expect(udpR.SrcPort).To(Equal(layers.UDPPort(testVxlanPort)))
110109
Expect(udpR.DstPort).To(Equal(layers.UDPPort(testVxlanPort)))
111110
Expect(udpR.Checksum).To(Equal(uint16(0)))
112111

@@ -175,7 +174,6 @@ func getVxlanVNI(pktR gopacket.Packet) uint32 {
175174
udpL := pktR.Layer(layers.LayerTypeUDP)
176175
Expect(udpL).NotTo(BeNil())
177176
udpR := udpL.(*layers.UDP)
178-
Expect(udpR.SrcPort).To(Equal(layers.UDPPort(testVxlanPort)))
179177
Expect(udpR.DstPort).To(Equal(layers.UDPPort(testVxlanPort)))
180178
Expect(udpR.Checksum).To(Equal(uint16(0)))
181179

felix/bpf/ut/nat_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,8 @@ func TestNATNodePort(t *testing.T) {
767767

768768
dumpCTMap(ctMap)
769769

770+
var vxlanSrcPort layers.UDPPort
771+
770772
skbMark = 0
771773
// Another pkt arriving at node 1 - uses existing CT entries
772774
runBpfTest(t, "calico_from_host_ep", nil, func(bpfrun bpfProgRunFn) {
@@ -783,9 +785,44 @@ func TestNATNodePort(t *testing.T) {
783785
Expect(ipv4R.SrcIP.String()).To(Equal(hostIP.String()))
784786
Expect(ipv4R.DstIP.String()).To(Equal(node2ip.String()))
785787

788+
udpL := pktR.Layer(layers.LayerTypeUDP)
789+
Expect(udpL).NotTo(BeNil())
790+
udpR := udpL.(*layers.UDP)
791+
792+
Expect(udpR.SrcPort).To(Equal(udp.SrcPort ^ udp.DstPort))
793+
vxlanSrcPort = udpR.SrcPort
794+
786795
checkVxlanEncap(pktR, false, ipv4, udp, payload)
787796
})
788797

798+
skbMark = 0
799+
// Another pkt iwith a different source port arriving at node 1
800+
runBpfTest(t, "calico_from_host_ep", nil, func(bpfrun bpfProgRunFn) {
801+
802+
// Change the source port
803+
pktBytes[14+(20+8)] = 0xde
804+
pktBytes[14+(20+8)+1] = 0xad
805+
806+
res, err := bpfrun(pktBytes)
807+
Expect(err).NotTo(HaveOccurred())
808+
Expect(res.Retval).To(Equal(resTC_ACT_UNSPEC))
809+
810+
pktR := gopacket.NewPacket(res.dataOut, layers.LayerTypeEthernet, gopacket.Default)
811+
fmt.Printf("pktR = %+v\n", pktR)
812+
813+
ipv4L := pktR.Layer(layers.LayerTypeIPv4)
814+
Expect(ipv4L).NotTo(BeNil())
815+
ipv4R := ipv4L.(*layers.IPv4)
816+
Expect(ipv4R.SrcIP.String()).To(Equal(hostIP.String()))
817+
Expect(ipv4R.DstIP.String()).To(Equal(node2ip.String()))
818+
819+
udpL := pktR.Layer(layers.LayerTypeUDP)
820+
Expect(udpL).NotTo(BeNil())
821+
udpR := udpL.(*layers.UDP)
822+
823+
Expect(udpR.SrcPort).NotTo(Equal(vxlanSrcPort))
824+
})
825+
789826
expectMark(tcdefs.MarkSeenBypassForward)
790827

791828
/*

0 commit comments

Comments
 (0)