srv6-as: Adding support for L2 traffic

Change-Id: I72978c5957cb1acf154c9de7ad153092bac37785
Signed-off-by: Francois Clad <fclad@cisco.com>
This commit is contained in:
Francois Clad
2018-07-04 11:47:21 +02:00
committed by Damjan Marion
parent 0928da903f
commit b02f3b7b8a
4 changed files with 442 additions and 38 deletions

View File

@ -121,18 +121,21 @@ srv6_as_localsid_creation_fn (ip6_sr_localsid_t * localsid)
/* Retrieve the adjacency corresponding to the (OIF, next_hop) */
adj_index_t nh_adj_index = ADJ_INDEX_INVALID;
if (ls_mem->ip_version == DA_IP4)
nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
VNET_LINK_IP4, &ls_mem->nh_addr,
ls_mem->sw_if_index_out);
else if (ls_mem->ip_version == DA_IP6)
nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
VNET_LINK_IP6, &ls_mem->nh_addr,
ls_mem->sw_if_index_out);
if (nh_adj_index == ADJ_INDEX_INVALID)
if (ls_mem->inner_type != AS_TYPE_L2)
{
free_ls_mem (ls_mem);
return SID_CREATE_INVALID_ADJ_INDEX;
if (ls_mem->inner_type == AS_TYPE_IP4)
nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
VNET_LINK_IP4, &ls_mem->nh_addr,
ls_mem->sw_if_index_out);
else if (ls_mem->inner_type == AS_TYPE_IP6)
nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
VNET_LINK_IP6, &ls_mem->nh_addr,
ls_mem->sw_if_index_out);
if (nh_adj_index == ADJ_INDEX_INVALID)
{
free_ls_mem (ls_mem);
return SID_CREATE_INVALID_ADJ_INDEX;
}
}
ls_mem->nh_adj = nh_adj_index;
@ -159,7 +162,37 @@ srv6_as_localsid_creation_fn (ip6_sr_localsid_t * localsid)
return SID_CREATE_INVALID_IFACE_TYPE;
}
if (ls_mem->ip_version == DA_IP4)
if (ls_mem->inner_type == AS_TYPE_L2)
{
/* Enable End.AS2 rewrite node for this interface */
int ret =
vnet_feature_enable_disable ("device-input", "srv6-as2-rewrite",
ls_mem->sw_if_index_in, 1, 0, 0);
if (ret != 0)
{
free_ls_mem (ls_mem);
return SID_CREATE_IFACE_FEATURE_ERROR;
}
/* Set interface in promiscuous mode */
vnet_main_t *vnm = vnet_get_main ();
ethernet_set_flags (vnm, ls_mem->sw_if_index_in,
ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
/* Prepare rewrite string */
ls_mem->rewrite = prepare_rewrite (ls_mem->src_addr, ls_mem->sid_list,
IP_PROTOCOL_IP6_NONXT);
/* Associate local SID index to this interface (resize vector if needed) */
if (ls_mem->sw_if_index_in >= vec_len (sm->sw_iface_localsid2))
{
vec_resize (sm->sw_iface_localsid2,
(pool_len (sm->vnet_main->interface_main.sw_interfaces)
- vec_len (sm->sw_iface_localsid2)));
}
sm->sw_iface_localsid2[ls_mem->sw_if_index_in] = localsid_index;
}
else if (ls_mem->inner_type == AS_TYPE_IP4)
{
/* Enable End.AS4 rewrite node for this interface */
int ret =
@ -185,7 +218,7 @@ srv6_as_localsid_creation_fn (ip6_sr_localsid_t * localsid)
}
sm->sw_iface_localsid4[ls_mem->sw_if_index_in] = localsid_index;
}
else if (ls_mem->ip_version == DA_IP6)
else if (ls_mem->inner_type == AS_TYPE_IP6)
{
/* Enable End.AS6 rewrite node for this interface */
int ret =
@ -233,7 +266,23 @@ srv6_as_localsid_removal_fn (ip6_sr_localsid_t * localsid)
srv6_as_main_t *sm = &srv6_as_main;
srv6_as_localsid_t *ls_mem = localsid->plugin_mem;
if (ls_mem->ip_version == DA_IP4)
if (ls_mem->inner_type == AS_TYPE_L2)
{
/* Disable End.AS2 rewrite node for this interface */
int ret;
ret = vnet_feature_enable_disable ("device-input", "srv6-as2-rewrite",
ls_mem->sw_if_index_in, 0, 0, 0);
if (ret != 0)
return -1;
/* Disable promiscuous mode on the interface */
vnet_main_t *vnm = vnet_get_main ();
ethernet_set_flags (vnm, ls_mem->sw_if_index_in, 0);
/* Remove local SID index from interface table */
sm->sw_iface_localsid2[ls_mem->sw_if_index_in] = ~(u32) 0;
}
else if (ls_mem->inner_type == AS_TYPE_IP4)
{
/* Disable End.AS4 rewrite node for this interface */
int ret;
@ -245,7 +294,7 @@ srv6_as_localsid_removal_fn (ip6_sr_localsid_t * localsid)
/* Remove local SID index from interface table */
sm->sw_iface_localsid4[ls_mem->sw_if_index_in] = ~(u32) 0;
}
else if (ls_mem->ip_version == DA_IP6)
else if (ls_mem->inner_type == AS_TYPE_IP6)
{
/* Disable End.AS6 rewrite node for this interface */
int ret;
@ -285,20 +334,20 @@ format_srv6_as_localsid (u8 * s, va_list * args)
vnet_main_t *vnm = vnet_get_main ();
srv6_as_main_t *sm = &srv6_as_main;
if (ls_mem->ip_version == DA_IP4)
if (ls_mem->inner_type == AS_TYPE_IP4)
{
s =
format (s, "Next-hop:\t%U\n", format_ip4_address,
format (s, "Next-hop:\t%U\n\t", format_ip4_address,
&ls_mem->nh_addr.ip4);
}
else
else if (ls_mem->inner_type == AS_TYPE_IP6)
{
s =
format (s, "Next-hop:\t%U\n", format_ip6_address,
format (s, "Next-hop:\t%U\n\t", format_ip6_address,
&ls_mem->nh_addr.ip6);
}
s = format (s, "\tOutgoing iface:\t%U\n", format_vnet_sw_if_index_name, vnm,
s = format (s, "Outgoing iface:\t%U\n", format_vnet_sw_if_index_name, vnm,
ls_mem->sw_if_index_out);
s = format (s, "\tIncoming iface:\t%U\n", format_vnet_sw_if_index_name, vnm,
ls_mem->sw_if_index_in);
@ -342,7 +391,7 @@ unformat_srv6_as_localsid (unformat_input_t * input, va_list * args)
vnet_main_t *vnm = vnet_get_main ();
u8 ip_version = 0;
u8 inner_type = AS_TYPE_L2;
ip46_address_t nh_addr;
u32 sw_if_index_out;
u32 sw_if_index_in;
@ -365,14 +414,14 @@ unformat_srv6_as_localsid (unformat_input_t * input, va_list * args)
unformat_ip4_address,
&nh_addr.ip4))
{
ip_version = DA_IP4;
inner_type = AS_TYPE_IP4;
params |= PARAM_AS_NH;
}
if (!(params & PARAM_AS_NH) && unformat (input, "nh %U",
unformat_ip6_address,
&nh_addr.ip6))
{
ip_version = DA_IP6;
inner_type = AS_TYPE_IP6;
params |= PARAM_AS_NH;
}
else if (!(params & PARAM_AS_OIF) && unformat (input, "oif %U",
@ -404,7 +453,7 @@ unformat_srv6_as_localsid (unformat_input_t * input, va_list * args)
}
/* Make sure that all parameters are supplied */
u8 params_chk = (PARAM_AS_NH | PARAM_AS_OIF | PARAM_AS_IIF | PARAM_AS_SRC);
u8 params_chk = (PARAM_AS_OIF | PARAM_AS_IIF | PARAM_AS_SRC);
if ((params & params_chk) != params_chk || sid_list == NULL)
{
vec_free (sid_list);
@ -417,10 +466,10 @@ unformat_srv6_as_localsid (unformat_input_t * input, va_list * args)
*plugin_mem_p = ls_mem;
/* Set local SID parameters */
ls_mem->ip_version = ip_version;
if (ip_version == DA_IP4)
ls_mem->inner_type = inner_type;
if (inner_type == AS_TYPE_IP4)
ls_mem->nh_addr.ip4 = nh_addr.ip4;
else
else if (inner_type == AS_TYPE_IP6)
ls_mem->nh_addr.ip6 = nh_addr.ip6;
ls_mem->sw_if_index_out = sw_if_index_out;
ls_mem->sw_if_index_in = sw_if_index_in;
@ -499,6 +548,13 @@ srv6_as_init (vlib_main_t * vm)
}
/* *INDENT-OFF* */
VNET_FEATURE_INIT (srv6_as2_rewrite, static) =
{
.arc_name = "device-input",
.node_name = "srv6-as2-rewrite",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (srv6_as4_rewrite, static) =
{
.arc_name = "ip4-unicast",

View File

@ -23,8 +23,9 @@
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
#define DA_IP4 4
#define DA_IP6 6
#define AS_TYPE_L2 2
#define AS_TYPE_IP4 4
#define AS_TYPE_IP6 6
/*
* This is the memory that will be stored per each localsid
@ -35,7 +36,7 @@ typedef struct
ip46_address_t nh_addr; /**< Proxied device address */
u32 sw_if_index_out; /**< Outgoing iface to proxied dev. */
u32 nh_adj; /**< Adjacency index for out. iface */
u8 ip_version;
u8 inner_type;
u32 sw_if_index_in; /**< Incoming iface from proxied dev. */
u8 *rewrite; /**< Headers to be rewritten */
@ -57,6 +58,7 @@ typedef struct
u32 srv6_localsid_behavior_id; /**< SRv6 LocalSID behavior number */
u32 *sw_iface_localsid2; /**< Retrieve local SID from iface */
u32 *sw_iface_localsid4; /**< Retrieve local SID from iface */
u32 *sw_iface_localsid6; /**< Retrieve local SID from iface */

View File

@ -92,6 +92,7 @@ typedef enum
SRV6_AS_LOCALSID_NEXT_ERROR,
SRV6_AS_LOCALSID_NEXT_REWRITE4,
SRV6_AS_LOCALSID_NEXT_REWRITE6,
SRV6_AS_LOCALSID_NEXT_INTERFACE,
SRV6_AS_LOCALSID_N_NEXT,
} srv6_as_localsid_next_t;
@ -129,9 +130,10 @@ end_as_processing (vlib_buffer_t * b0,
ext_hdr = ip6_ext_next_header (ext_hdr);
}
/* Make sure next header is IP */
/* Make sure next header is valid */
if (PREDICT_FALSE (hdr_type != IP_PROTOCOL_IPV6 &&
hdr_type != IP_PROTOCOL_IP_IN_IP))
hdr_type != IP_PROTOCOL_IP_IN_IP &&
hdr_type != IP_PROTOCOL_IP6_NONXT))
{
return;
}
@ -139,13 +141,23 @@ end_as_processing (vlib_buffer_t * b0,
/* Remove IP header and extensions */
vlib_buffer_advance (b0, encap_len);
/* Set Xconnect adjacency to VNF */
vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
if (hdr_type == IP_PROTOCOL_IP6_NONXT)
{
/* Set output interface */
vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0_mem->sw_if_index_out;
if (ls0_mem->ip_version == DA_IP4)
*next0 = SRV6_AS_LOCALSID_NEXT_REWRITE4;
else if (ls0_mem->ip_version == DA_IP6)
*next0 = SRV6_AS_LOCALSID_NEXT_REWRITE6;
/* Set next node to interface-output */
*next0 = SRV6_AS_LOCALSID_NEXT_INTERFACE;
}
else
{
/* Set Xconnect adjacency to VNF */
vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
/* Set next node to ip-rewrite */
*next0 = (hdr_type == IP_PROTOCOL_IPV6) ?
SRV6_AS_LOCALSID_NEXT_REWRITE6 : SRV6_AS_LOCALSID_NEXT_REWRITE4;
}
}
/**
@ -236,6 +248,7 @@ VLIB_REGISTER_NODE (srv6_as_localsid_node) = {
.next_nodes = {
[SRV6_AS_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
[SRV6_AS_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
[SRV6_AS_LOCALSID_NEXT_INTERFACE] = "interface-output",
[SRV6_AS_LOCALSID_NEXT_ERROR] = "error-drop",
},
};
@ -244,6 +257,140 @@ VLIB_REGISTER_NODE (srv6_as_localsid_node) = {
/******************************* Rewriting node *******************************/
/**
* @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
*/
static uword
srv6_as2_rewrite_fn (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
ip6_sr_main_t *srm = &sr_main;
srv6_as_main_t *sm = &srv6_as_main;
u32 n_left_from, next_index, *from, *to_next;
u32 cnt_packets = 0;
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
while (n_left_from > 0)
{
u32 n_left_to_next;
vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
/* TODO: Dual/quad loop */
while (n_left_from > 0 && n_left_to_next > 0)
{
u32 bi0;
vlib_buffer_t *b0;
ethernet_header_t *en0;
ip6_header_t *ip0 = 0;
ip6_sr_localsid_t *ls0;
srv6_as_localsid_t *ls0_mem;
u32 next0 = SRV6_AS_REWRITE_NEXT_LOOKUP;
bi0 = from[0];
to_next[0] = bi0;
from += 1;
to_next += 1;
n_left_from -= 1;
n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
en0 = vlib_buffer_get_current (b0);
ls0 = pool_elt_at_index (srm->localsids,
sm->sw_iface_localsid2[vnet_buffer
(b0)->sw_if_index
[VLIB_RX]]);
ls0_mem = ls0->plugin_mem;
if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
{
next0 = SRV6_AS_REWRITE_NEXT_ERROR;
b0->error = node->errors[SRV6_AS_REWRITE_COUNTER_NO_RW];
}
else
{
ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
(vec_len (ls0_mem->rewrite) + b0->current_data));
clib_memcpy (((u8 *) en0) - vec_len (ls0_mem->rewrite),
ls0_mem->rewrite, vec_len (ls0_mem->rewrite));
vlib_buffer_advance (b0, -(word) vec_len (ls0_mem->rewrite));
ip0 = vlib_buffer_get_current (b0);
ip0->payload_length =
clib_host_to_net_u16 (b0->current_length -
sizeof (ip6_header_t));
}
if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
srv6_as_rewrite_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof *tr);
tr->error = 0;
if (next0 == SRV6_AS_REWRITE_NEXT_ERROR)
{
tr->error = 1;
}
else
{
clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
sizeof tr->src.as_u8);
clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
sizeof tr->dst.as_u8);
}
}
/* Increment per-SID AS rewrite counters */
vlib_increment_combined_counter (((next0 ==
SRV6_AS_LOCALSID_NEXT_ERROR) ?
&(sm->invalid_counters) :
&(sm->valid_counters)),
vm->thread_index, ls0_mem->index,
1, vlib_buffer_length_in_chain (vm,
b0));
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, next0);
cnt_packets++;
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
/* Update counters */
vlib_node_increment_counter (vm, srv6_as4_rewrite_node.index,
SRV6_AS_REWRITE_COUNTER_PROCESSED,
cnt_packets);
return frame->n_vectors;
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (srv6_as2_rewrite_node) = {
.function = srv6_as2_rewrite_fn,
.name = "srv6-as2-rewrite",
.vector_size = sizeof (u32),
.format_trace = format_srv6_as_rewrite_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = SRV6_AS_REWRITE_N_COUNTERS,
.error_strings = srv6_as_rewrite_counter_strings,
.n_next_nodes = SRV6_AS_REWRITE_N_NEXT,
.next_nodes = {
[SRV6_AS_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
[SRV6_AS_REWRITE_NEXT_ERROR] = "error-drop",
},
};
/* *INDENT-ON* */
/**
* @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
*/

199
test/test_srv6_as.py Normal file → Executable file
View File

@ -162,6 +162,93 @@ class TestSRv6(VppTestCase):
test_sid_index=0,
rewrite_src_addr='a1::')
def test_SRv6_End_AS_L2_noSRH(self):
""" Test SRv6 End.AS behavior with L2 traffic and no SRH rewrite.
"""
self.run_SRv6_End_AS_L2(
sid_list=['a1::', 'a2::a6', 'a3::'],
test_sid_index=1,
rewrite_src_addr='a2::')
def test_SRv6_End_AS_L2_SRH(self):
""" Test SRv6 End.AS behavior with L2 traffic and SRH rewrite.
"""
self.run_SRv6_End_AS_L2(
sid_list=['a1::a6', 'a2::', 'a3::'],
test_sid_index=0,
rewrite_src_addr='a1::')
def run_SRv6_End_AS_L2(self, sid_list, test_sid_index, rewrite_src_addr):
""" Run SRv6 End.AS test with L2 traffic.
"""
self.rewrite_src_addr = rewrite_src_addr
self.rewrite_sid_list = sid_list[test_sid_index + 1::]
# send traffic to one destination interface
# source and destination interfaces are IPv6 only
self.setup_interfaces(ipv6=[True, False])
# configure route to next segment
route = VppIpRoute(self, sid_list[test_sid_index + 1], 128,
[VppRoutePath(self.pg0.remote_ip6,
self.pg0.sw_if_index,
proto=DpoProto.DPO_PROTO_IP6)],
is_ip6=1)
route.add_vpp_config()
# configure SRv6 localSID behavior
cli_str = "sr localsid address " + sid_list[test_sid_index] \
+ " behavior end.as" \
+ " oif " + self.pg1.name \
+ " iif " + self.pg1.name \
+ " src " + self.rewrite_src_addr
for s in self.rewrite_sid_list:
cli_str += " next " + s
self.vapi.cli(cli_str)
# log the localsids
self.logger.debug(self.vapi.cli("show sr localsid"))
# send one packet per packet size
count = len(self.pg_packet_sizes)
# prepare L2 in SRv6 headers
packet_header1 = self.create_packet_header_IPv6_SRH_L2(
sidlist=sid_list[::-1],
segleft=len(sid_list) - test_sid_index - 1,
vlan=0)
# generate packets (pg0->pg1)
pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1,
self.pg_packet_sizes, count)
# send packets and verify received packets
self.send_and_verify_pkts(self.pg0, pkts1, self.pg1,
self.compare_rx_tx_packet_End_AS_L2_out)
# log the localsid counters
self.logger.info(self.vapi.cli("show sr localsid"))
# prepare L2 header for returning packets
packet_header2 = self.create_packet_header_L2()
# generate returning packets (pg1->pg0)
pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2,
self.pg_packet_sizes, count)
# send packets and verify received packets
self.send_and_verify_pkts(self.pg1, pkts2, self.pg0,
self.compare_rx_tx_packet_End_AS_L2_in)
# log the localsid counters
self.logger.info(self.vapi.cli("show sr localsid"))
# remove SRv6 localSIDs
self.vapi.cli("sr localsid del address " + sid_list[test_sid_index])
# cleanup interfaces
self.teardown_interfaces()
def run_SRv6_End_AS_IPv6(self, sid_list, test_sid_index, rewrite_src_addr):
""" Run SRv6 End.AS test with IPv6 traffic.
"""
@ -407,6 +494,53 @@ class TestSRv6(VppTestCase):
self.logger.debug("packet verification: SUCCESS")
def compare_rx_tx_packet_End_AS_L2_in(self, tx_pkt, rx_pkt):
""" Compare input and output packet after passing End.AS
:param tx_pkt: transmitted packet
:param rx_pkt: received packet
"""
# get first (outer) IPv6 header of rx'ed packet
rx_ip = rx_pkt.getlayer(IPv6)
rx_srh = None
tx_ether = tx_pkt.getlayer(Ether)
# expected segment-list (SRH order)
tx_seglist = self.rewrite_sid_list[::-1]
# received ip.src should be equal to SR Policy source
self.assertEqual(rx_ip.src, self.rewrite_src_addr)
# received ip.dst should be equal to expected sidlist[lastentry]
self.assertEqual(rx_ip.dst, tx_seglist[-1])
if len(tx_seglist) > 1:
# rx'ed packet should have SRH
self.assertTrue(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting))
# get SRH
rx_srh = rx_pkt.getlayer(IPv6ExtHdrSegmentRouting)
# rx'ed seglist should be equal to seglist
self.assertEqual(rx_srh.addresses, tx_seglist)
# segleft should be equal to size seglist-1
self.assertEqual(rx_srh.segleft, len(tx_seglist)-1)
# segleft should be equal to lastentry
self.assertEqual(rx_srh.segleft, rx_srh.lastentry)
# nh should be "No Next Header" (59)
self.assertEqual(rx_srh.nh, 59)
# get payload
payload = rx_srh.payload
else:
# rx'ed packet should NOT have SRH
self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting))
# get payload
payload = rx_ip.payload
# the whole rx'ed pkt beyond SRH should be equal to tx'ed pkt
self.assertEqual(Ether(str(payload)), tx_ether)
self.logger.debug("packet verification: SUCCESS")
def compare_rx_tx_packet_End_AS_IPv6_out(self, tx_pkt, rx_pkt):
""" Compare input and output packet after passing End.AS with IPv6
@ -462,6 +596,29 @@ class TestSRv6(VppTestCase):
self.logger.debug("packet verification: SUCCESS")
def compare_rx_tx_packet_End_AS_L2_out(self, tx_pkt, rx_pkt):
""" Compare input and output packet after passing End.AS with L2
:param tx_pkt: transmitted packet
:param rx_pkt: received packet
"""
# get IPv4 header of rx'ed packet
rx_eth = rx_pkt.getlayer(Ether)
tx_ip = tx_pkt.getlayer(IPv6)
# we can't just get the 2nd Ether layer
# get the Raw content and dissect it as Ether
tx_eth1 = Ether(str(tx_pkt[Raw]))
# verify if rx'ed packet has no SRH
self.assertFalse(rx_pkt.haslayer(IPv6ExtHdrSegmentRouting))
# the whole rx_eth pkt should be equal to tx_eth1
self.assertEqual(rx_eth, tx_eth1)
self.logger.debug("packet verification: SUCCESS")
def create_stream(self, src_if, dst_if, packet_header, packet_sizes,
count):
"""Create SRv6 input packet stream for defined interface.
@ -604,6 +761,48 @@ class TestSRv6(VppTestCase):
UDP(sport=1234, dport=1234))
return p
def create_packet_header_L2(self, vlan=0):
"""Create packet header: L2 header
:param vlan: if vlan!=0 then add 802.1q header
"""
# Note: the dst addr ('00:55:44:33:22:11') is used in
# the compare function compare_rx_tx_packet_T_Encaps_L2
# to detect presence of L2 in SRH payload
p = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11')
etype = 0x8137 # IPX
if vlan:
# add 802.1q layer
p /= Dot1Q(vlan=vlan, type=etype)
else:
p.type = etype
return p
def create_packet_header_IPv6_SRH_L2(self, sidlist, segleft, vlan=0):
"""Create packet header: L2 encapsulated in SRv6:
IPv6 header with SRH, L2
:param list sidlist: segment list of outer IPv6 SRH
:param int segleft: segments-left field of outer IPv6 SRH
:param vlan: L2 vlan; if vlan!=0 then add 802.1q header
Outer IPv6 destination address is set to sidlist[segleft]
IPv6 source address is 1234::1
"""
eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11')
etype = 0x8137 # IPX
if vlan:
# add 802.1q layer
eth /= Dot1Q(vlan=vlan, type=etype)
else:
eth.type = etype
p = (IPv6(src='1234::1', dst=sidlist[segleft]) /
IPv6ExtHdrSegmentRouting(addresses=sidlist,
segleft=segleft, nh=59) /
eth)
return p
def get_payload_info(self, packet):
""" Extract the payload_info from the packet
"""