diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index 7d1dc9c1d05..3de1537b45e 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -27,6 +27,7 @@ #include #include #include +#include /* l2 connection type */ typedef enum l2_input_flags_t_ @@ -327,7 +328,7 @@ vnet_update_l2_len (vlib_buffer_t *b) /* * Compute flow hash of an ethernet packet, use 5-tuple hash if L3 packet - * is ip4 or ip6. Otherwise hash on smac/dmac/etype. + * is ip4, ip6, or mpls. Otherwise hash on smac/dmac/etype. * The vlib buffer current pointer is expected to be at ethernet header * and vnet l2.l2_len is expected to be setup already. */ @@ -342,6 +343,9 @@ vnet_l2_compute_flow_hash (vlib_buffer_t * b) return ip4_compute_flow_hash ((ip4_header_t *) l3h, IP_FLOW_HASH_DEFAULT); else if (ethertype == ETHERNET_TYPE_IP6) return ip6_compute_flow_hash ((ip6_header_t *) l3h, IP_FLOW_HASH_DEFAULT); + else if (ethertype == ETHERNET_TYPE_MPLS) + return mpls_compute_flow_hash ((mpls_unicast_header_t *) l3h, + IP_FLOW_HASH_DEFAULT); else { u32 a, b, c; diff --git a/test/template_bd.py b/test/template_bd.py index 55aaa5a8f4c..07e824af5a8 100644 --- a/test/template_bd.py +++ b/test/template_bd.py @@ -5,6 +5,8 @@ import abc from scapy.layers.l2 import Ether from scapy.packet import Raw from scapy.layers.inet import IP, UDP +from scapy.layers.inet6 import IPv6 +from scapy.contrib.mpls import MPLS class BridgeDomain(metaclass=abc.ABCMeta): @@ -61,8 +63,16 @@ class BridgeDomain(metaclass=abc.ABCMeta): """ self.assertEqual(pkt1[Ether].src, pkt2[Ether].src) self.assertEqual(pkt1[Ether].dst, pkt2[Ether].dst) - self.assertEqual(pkt1[IP].src, pkt2[IP].src) - self.assertEqual(pkt1[IP].dst, pkt2[IP].dst) + if MPLS in pkt1 or MPLS in pkt2: + self.assertEqual(pkt1[MPLS].label, pkt2[MPLS].label) + self.assertEqual(pkt1[MPLS].cos, pkt2[MPLS].cos) + self.assertEqual(pkt1[MPLS].ttl, pkt2[MPLS].ttl) + if IP in pkt1 or IP in pkt2: + self.assertEqual(pkt1[IP].src, pkt2[IP].src) + self.assertEqual(pkt1[IP].dst, pkt2[IP].dst) + elif IPv6 in pkt1 or IPv6 in pkt2: + self.assertEqual(pkt1[IPv6].src, pkt2[IPv6].src) + self.assertEqual(pkt1[IPv6].dst, pkt2[IPv6].dst) self.assertEqual(pkt1[UDP].sport, pkt2[UDP].sport) self.assertEqual(pkt1[UDP].dport, pkt2[UDP].dport) self.assertEqual(pkt1[Raw], pkt2[Raw]) diff --git a/test/test_vxlan.py b/test/test_vxlan.py index 876664ddbdc..6128d1070d3 100644 --- a/test/test_vxlan.py +++ b/test/test_vxlan.py @@ -11,7 +11,9 @@ from scapy.layers.l2 import Ether from scapy.layers.l2 import ARP from scapy.packet import Raw, bind_layers from scapy.layers.inet import IP, UDP +from scapy.layers.inet6 import IPv6 from scapy.layers.vxlan import VXLAN +from scapy.contrib.mpls import MPLS import util from vpp_ip_route import VppIpRoute, VppRoutePath @@ -287,6 +289,71 @@ class TestVxlan(BridgeDomain, VppTestCase): # Set scapy listen custom port for VxLAN bind_layers(UDP, VXLAN, dport=self.dport) + def encap_packets(self): + def encap_frames(frame, n=10): + frames = [] + + # Provide IP flow hash difference. + for i in range(n): + p = frame.copy() + p[UDP].dport += i + frames.append(p) + + self.pg1.add_stream(frames) + + self.pg0.enable_capture() + self.pg_start() + + # Pick received frames and check if they're correctly encapsulated. + out = self.pg0.get_capture(n) + sports = set() + for i in range(n): + pkt = out[i] + self.check_encapsulation(pkt, self.single_tunnel_vni) + + payload = self.decapsulate(pkt) + self.assert_eq_pkts(payload, frames[i]) + + sports.add(pkt[UDP].sport) + + # Check src port randomization presence, not concerned with the + # src ports split ratio, just as long as there are more then one. + self.assertGreaterEqual(len(sports), min(n, 2)) + + frame_ip4 = ( + Ether(src="00:00:00:00:00:02", dst="00:00:00:00:00:01") + / IP(src="4.3.2.1", dst="1.2.3.4") + / UDP(sport=20000, dport=10000) + / Raw("\xa5" * 100) + ) + encap_frames(frame_ip4) + + frame_ip6 = ( + Ether(src="00:00:00:00:00:02", dst="00:00:00:00:00:01") + / IPv6(src="2001:db8::4321", dst="2001:db8::1234") + / UDP(sport=20000, dport=10000) + / Raw("\xa5" * 100) + ) + encap_frames(frame_ip6) + + frame_mpls4 = ( + Ether(src="00:00:00:00:00:02", dst="00:00:00:00:00:01") + / MPLS(label=44, ttl=64) + / IP(src="4.3.2.1", dst="1.2.3.4") + / UDP(sport=20000, dport=10000) + / Raw("\xa5" * 100) + ) + encap_frames(frame_mpls4) + + frame_mpls6 = ( + Ether(src="00:00:00:00:00:02", dst="00:00:00:00:00:01") + / MPLS(label=44, ttl=64) + / IPv6(src="2001:db8::4321", dst="2001:db8::1234") + / UDP(sport=20000, dport=10000) + / Raw("\xa5" * 100) + ) + encap_frames(frame_mpls6) + def encap_big_packet(self): self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1500, 0, 0, 0]) @@ -330,7 +397,7 @@ class TestVxlan(BridgeDomain, VppTestCase): from BridgeDoman """ self.createVxLANInterfaces() - super(TestVxlan, self).test_encap() + self.encap_packets() def test_encap_big_packet(self): """Encapsulation test send big frame from pg1