Fix ERSPAN encap to set EN bits in the header and add test case
For ERSPAN encap, both bits in the EN field of the header should be set to indicate any VLAN tag in the original Ethernet frame is preserved. Added SPAN L2 test case where the mirrored packet output is a GRE ERSPAN tunnel. Change-Id: Ie7a40992a9278469c24aa6fa9e122b4505797d10 Signed-off-by: John Lo <loj@cisco.com>
This commit is contained in:
@ -410,10 +410,10 @@ gre_interface_tx (vlib_main_t * vm,
|
||||
vlib_buffer_advance (b0, -sizeof (erspan_t2_t));
|
||||
erspan_t2_t *h0 = vlib_buffer_get_current (b0);
|
||||
u32 seq_num = clib_smp_atomic_add (>0->gre_sn->seq_num, 1);
|
||||
u64 ver1 = clib_host_to_net_u64 (0x1000000000000000);
|
||||
u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
|
||||
h0->seq_num = clib_host_to_net_u32 (seq_num);
|
||||
h0->t2_u64 = ver1; /* all 0's except ver=1 */
|
||||
h0->t2.cos_en_t_session =
|
||||
h0->t2_u64 = hdr;
|
||||
h0->t2.cos_en_t_session |=
|
||||
clib_host_to_net_u16 (gt0->session_id);
|
||||
}
|
||||
if (PREDICT_FALSE (gt1->type == GRE_TUNNEL_TYPE_ERSPAN))
|
||||
@ -422,10 +422,10 @@ gre_interface_tx (vlib_main_t * vm,
|
||||
vlib_buffer_advance (b1, -sizeof (erspan_t2_t));
|
||||
erspan_t2_t *h1 = vlib_buffer_get_current (b1);
|
||||
u32 seq_num = clib_smp_atomic_add (>1->gre_sn->seq_num, 1);
|
||||
u64 ver1 = clib_host_to_net_u64 (0x1000000000000000);
|
||||
u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
|
||||
h1->seq_num = clib_host_to_net_u32 (seq_num);
|
||||
h1->t2_u64 = ver1; /* all 0's except ver=1 */
|
||||
h1->t2.cos_en_t_session =
|
||||
h1->t2_u64 = hdr;
|
||||
h1->t2.cos_en_t_session |=
|
||||
clib_host_to_net_u16 (gt1->session_id);
|
||||
}
|
||||
|
||||
@ -481,10 +481,10 @@ gre_interface_tx (vlib_main_t * vm,
|
||||
vlib_buffer_advance (b0, -sizeof (erspan_t2_t));
|
||||
erspan_t2_t *h0 = vlib_buffer_get_current (b0);
|
||||
u32 seq_num = clib_smp_atomic_add (>0->gre_sn->seq_num, 1);
|
||||
u64 ver1 = clib_host_to_net_u64 (0x1000000000000000);
|
||||
u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
|
||||
h0->seq_num = clib_host_to_net_u32 (seq_num);
|
||||
h0->t2_u64 = ver1; /* all 0's except ver=1 */
|
||||
h0->t2.cos_en_t_session =
|
||||
h0->t2_u64 = hdr;
|
||||
h0->t2.cos_en_t_session |=
|
||||
clib_host_to_net_u16 (gt0->session_id);
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,9 @@ typedef CLIB_PACKED (struct {
|
||||
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* u64 template for ERSPAN type 2 header with both EN bits set */
|
||||
#define ERSPAN_HDR2 0x1000180000000000ul
|
||||
|
||||
#endif /* included_vnet_gre_packet_h */
|
||||
|
||||
/*
|
||||
|
@ -14,12 +14,40 @@ diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py
|
||||
index 4f491d2..661a5da 100644
|
||||
--- a/scapy/layers/l2.py
|
||||
+++ b/scapy/layers/l2.py
|
||||
@@ -628,7 +628,7 @@ bind_layers( CookedLinux, EAPOL, proto=34958)
|
||||
@@ -570,6 +570,20 @@
|
||||
return getmacbyip(l3.pdst)
|
||||
conf.neighbor.register_l3(Ether, ARP, l2_register_l3_arp)
|
||||
|
||||
+
|
||||
+class ERSPAN(Packet):
|
||||
+ name = "ERSPAN"
|
||||
+ fields_desc = [ BitField("ver",0,4),
|
||||
+ BitField("vlan",0,12),
|
||||
+ BitField("cos",0,3),
|
||||
+ BitField("en",0,2),
|
||||
+ BitField("t",0,1),
|
||||
+ BitField("session_id",0,10),
|
||||
+ BitField("reserved",0,12),
|
||||
+ BitField("index",0,20),
|
||||
+ ]
|
||||
+
|
||||
+
|
||||
class GRErouting(Packet):
|
||||
name = "GRE routing informations"
|
||||
fields_desc = [ ShortField("address_family",0),
|
||||
@@ -628,12 +642,14 @@ bind_layers( CookedLinux, EAPOL, proto=34958)
|
||||
bind_layers( GRE, LLC, proto=122)
|
||||
bind_layers( GRE, Dot1Q, proto=33024)
|
||||
bind_layers( GRE, Dot1AD, type=0x88a8)
|
||||
-bind_layers( GRE, Ether, proto=1)
|
||||
+bind_layers( GRE, Ether, proto=0x6558)
|
||||
+bind_layers( GRE, ERSPAN, proto=0x88be, seqnum_present=1)
|
||||
bind_layers( GRE, ARP, proto=2054)
|
||||
bind_layers( GRE, EAPOL, proto=34958)
|
||||
bind_layers( GRE, GRErouting, { "routing_present" : 1 } )
|
||||
bind_layers( GRErouting, conf.raw_layer,{ "address_family" : 0, "SRE_len" : 0 })
|
||||
bind_layers( GRErouting, GRErouting, { } )
|
||||
+bind_layers( ERSPAN, Ether)
|
||||
bind_layers( EAPOL, EAP, type=0)
|
||||
bind_layers(EAP, EAP_TLS, type=13)
|
||||
bind_layers(EAP, EAP_FAST, type=43)
|
||||
|
@ -3,7 +3,7 @@
|
||||
import unittest
|
||||
|
||||
from scapy.packet import Raw
|
||||
from scapy.layers.l2 import Ether, Dot1Q, GRE
|
||||
from scapy.layers.l2 import Ether, Dot1Q, GRE, ERSPAN
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.layers.vxlan import VXLAN
|
||||
|
||||
@ -102,6 +102,27 @@ class TestSpan(VppTestCase):
|
||||
|
||||
return pkt[GRE].payload
|
||||
|
||||
def decap_erspan(self, pkt, session):
|
||||
"""
|
||||
Decapsulate the original payload frame by removing ERSPAN header
|
||||
"""
|
||||
self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
|
||||
self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
|
||||
|
||||
self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
|
||||
self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
|
||||
|
||||
self.assertEqual(pkt[ERSPAN].ver, 1)
|
||||
self.assertEqual(pkt[ERSPAN].vlan, 0)
|
||||
self.assertEqual(pkt[ERSPAN].cos, 0)
|
||||
self.assertEqual(pkt[ERSPAN].en, 3)
|
||||
self.assertEqual(pkt[ERSPAN].t, 0)
|
||||
self.assertEqual(pkt[ERSPAN].session_id, session)
|
||||
self.assertEqual(pkt[ERSPAN].reserved, 0)
|
||||
self.assertEqual(pkt[ERSPAN].index, 0)
|
||||
|
||||
return pkt[ERSPAN].payload
|
||||
|
||||
def decap_vxlan(self, pkt):
|
||||
"""
|
||||
Decapsulate the original payload frame by removing VXLAN header
|
||||
@ -245,6 +266,54 @@ class TestSpan(VppTestCase):
|
||||
self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
|
||||
self.verify_capture(pg1_pkts, pg2_pkts)
|
||||
|
||||
def test_span_l2_rx_dst_gre_erspan(self):
|
||||
""" SPAN l2 rx mirror into gre-erspan """
|
||||
|
||||
self.sub_if.admin_up()
|
||||
|
||||
gre_if = VppGreInterface(self, self.pg2.local_ip4,
|
||||
self.pg2.remote_ip4,
|
||||
type=2,
|
||||
session=543)
|
||||
|
||||
gre_if.add_vpp_config()
|
||||
gre_if.admin_up()
|
||||
|
||||
self.bridge(gre_if.sw_if_index)
|
||||
# Create bi-directional cross-connects between pg0 and pg1
|
||||
self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
|
||||
|
||||
# Create incoming packet streams for packet-generator interfaces
|
||||
pkts = self.create_stream(
|
||||
self.pg0, self.pg_if_packet_sizes, do_dot1=True)
|
||||
self.pg0.add_stream(pkts)
|
||||
|
||||
# Enable SPAN on pg0 sub if (mirrored to gre-erspan)
|
||||
self.vapi.sw_interface_span_enable_disable(
|
||||
self.sub_if.sw_if_index, gre_if.sw_if_index, is_l2=1)
|
||||
|
||||
# Enable packet capturing and start packet sending
|
||||
self.pg_enable_capture(self.pg_interfaces)
|
||||
self.pg_start()
|
||||
|
||||
# Verify packets outgoing packet streams on mirrored interface (pg2)
|
||||
n_pkts = len(pkts)
|
||||
pg1_pkts = self.pg1.get_capture(n_pkts)
|
||||
pg2_pkts = self.pg2.get_capture(n_pkts)
|
||||
|
||||
def decap(p): return self.decap_erspan(p, session=543)
|
||||
pg2_decaped = [decap(p) for p in pg2_pkts]
|
||||
|
||||
self.bridge(gre_if.sw_if_index, is_add=0)
|
||||
|
||||
# Disable SPAN on pg0 sub if
|
||||
self.vapi.sw_interface_span_enable_disable(
|
||||
self.sub_if.sw_if_index, gre_if.sw_if_index, state=0, is_l2=1)
|
||||
gre_if.remove_vpp_config()
|
||||
self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
|
||||
|
||||
self.verify_capture(pg1_pkts, pg2_decaped)
|
||||
|
||||
def test_span_l2_rx_dst_gre_subif_vtr(self):
|
||||
""" SPAN l2 rx mirror into gre-subif+vtr """
|
||||
|
||||
@ -270,6 +339,7 @@ class TestSpan(VppTestCase):
|
||||
self.pg0, self.pg_if_packet_sizes, do_dot1=True)
|
||||
self.pg0.add_stream(pkts)
|
||||
|
||||
# Enable SPAN on pg0 sub if (mirrored to gre sub if)
|
||||
self.vapi.sw_interface_span_enable_disable(
|
||||
self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1)
|
||||
|
||||
|
Reference in New Issue
Block a user