P2P Ethernet

Change-Id: Idb97e573961b3bc2acdeef77582314590795f8c3
Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
This commit is contained in:
Pavel Kotucek
2017-06-20 14:00:26 +02:00
committed by John Lo
parent 5b311202b8
commit 15ac81c16f
18 changed files with 1144 additions and 33 deletions
+12 -5
View File
@@ -19161,6 +19161,7 @@ api_p2p_ethernet_add (vat_main_t * vam)
unformat_input_t *i = vam->input;
vl_api_p2p_ethernet_add_t *mp;
u32 parent_if_index = ~0;
u32 sub_id = ~0;
u8 remote_mac[6];
u8 mac_set = 0;
int ret;
@@ -19176,6 +19177,8 @@ api_p2p_ethernet_add (vat_main_t * vam)
if (unformat
(i, "remote_mac %U", unformat_ethernet_address, remote_mac))
mac_set++;
else if (unformat (i, "sub_id %d", &sub_id))
;
else
{
clib_warning ("parse error '%U'", format_unformat_error, i);
@@ -19193,9 +19196,15 @@ api_p2p_ethernet_add (vat_main_t * vam)
errmsg ("missing remote mac address");
return -99;
}
if (sub_id == ~0)
{
errmsg ("missing sub-interface id");
return -99;
}
M (P2P_ETHERNET_ADD, mp);
mp->parent_if_index = ntohl (parent_if_index);
mp->subif_id = ntohl (sub_id);
clib_memcpy (mp->remote_mac, remote_mac, sizeof (remote_mac));
S (mp);
@@ -20094,11 +20103,10 @@ _(l2_xconnect_dump, "") \
_(sw_interface_set_mtu, "<intfc> | sw_if_index <nn> mtu <nn>") \
_(ip_neighbor_dump, "[ip6] <intfc> | sw_if_index <nn>") \
_(sw_interface_get_table, "<intfc> | sw_if_index <id> [ipv6]") \
_(p2p_ethernet_add, "<intfc> | sw_if_index <nn> remote_mac <mac-address>") \
_(p2p_ethernet_add, "<intfc> | sw_if_index <nn> remote_mac <mac-address> sub_id <id>") \
_(p2p_ethernet_del, "<intfc> | sw_if_index <nn> remote_mac <mac-address>") \
_(lldp_config, "system-name <name> tx-hold <nn> tx-interval <nn>") \
_(sw_interface_set_lldp, \
"<intfc> | sw_if_index <nn> [port-desc <description>] [disable]")
_(lldp_config, "system-name <name> tx-hold <nn> tx-interval <nn>") \
_(sw_interface_set_lldp, "<intfc> | sw_if_index <nn> [port-desc <description>] [disable]")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
@@ -20122,7 +20130,6 @@ _(search_node_table, "usage: search_node_table <name>...") \
_(set, "usage: set <variable-name> <value>") \
_(script, "usage: script <file-name>") \
_(unset, "usage: unset <variable-name>")
#define _(N,n) \
static void vl_api_##n##_t_handler_uni \
(vl_api_##n##_t * mp) \
+1
View File
@@ -115,6 +115,7 @@ libvnet_la_SOURCES += \
vnet/ethernet/pg.c \
vnet/ethernet/sfp.c \
vnet/ethernet/p2p_ethernet.c \
vnet/ethernet/p2p_ethernet_input.c \
vnet/ethernet/p2p_ethernet_api.c
nobase_include_HEADERS += \
+2 -1
View File
@@ -112,7 +112,8 @@ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \
_(BD_IN_USE, -120, "Bridge domain has member interfaces") \
_(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \
_(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \
_(UNSUPPORTED, -123, "Unsupported")
_(UNSUPPORTED, -123, "Unsupported") \
_(SUBIF_DOESNT_EXIST, -124, "Subinterface doesn't exist")
typedef enum
{
+6
View File
@@ -77,6 +77,12 @@ VNET_FEATURE_INIT (span_input, static) = {
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
.arc_name = "device-input",
.node_name = "p2p-ethernet-input",
.runs_before = VNET_FEATURES ("ethernet-input"),
};
VNET_FEATURE_INIT (ethernet_input, static) = {
.arc_name = "device-input",
.node_name = "ethernet-input",
+1
View File
@@ -169,6 +169,7 @@ typedef struct
#define SUBINT_CONFIG_MATCH_3_TAG (1<<3)
#define SUBINT_CONFIG_VALID (1<<4)
#define SUBINT_CONFIG_L2 (1<<5)
#define SUBINT_CONFIG_P2P (1<<6)
} subint_config_t;
+41 -13
View File
@@ -89,7 +89,10 @@ ethernet_build_rewrite (vnet_main_t * vnm,
ethernet_type_t type;
uword n_bytes = sizeof (h[0]);
u8 *rewrite = NULL;
u8 is_p2p = 0;
if (sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P)
is_p2p = 1;
if (sub_sw != sup_sw)
{
if (sub_sw->sub.eth.flags.one_tag)
@@ -100,13 +103,24 @@ ethernet_build_rewrite (vnet_main_t * vnm,
{
n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
}
// Check for encaps that are not supported for L3 interfaces
if (!(sub_sw->sub.eth.flags.exact_match) ||
(sub_sw->sub.eth.flags.default_sub) ||
(sub_sw->sub.eth.flags.outer_vlan_id_any) ||
(sub_sw->sub.eth.flags.inner_vlan_id_any))
else if (PREDICT_FALSE (is_p2p))
{
return 0;
n_bytes = sizeof (ethernet_header_t);
}
if (PREDICT_FALSE (!is_p2p))
{
// Check for encaps that are not supported for L3 interfaces
if (!(sub_sw->sub.eth.flags.exact_match) ||
(sub_sw->sub.eth.flags.default_sub) ||
(sub_sw->sub.eth.flags.outer_vlan_id_any) ||
(sub_sw->sub.eth.flags.inner_vlan_id_any))
{
return 0;
}
}
else
{
n_bytes = sizeof (ethernet_header_t);
}
}
@@ -126,12 +140,20 @@ ethernet_build_rewrite (vnet_main_t * vnm,
h = (ethernet_header_t *) rewrite;
ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
clib_memcpy (h->src_address, ei->address, sizeof (h->src_address));
if (dst_address)
clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
if (is_p2p)
{
clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
sizeof (h->dst_address));
}
else
memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
{
if (dst_address)
clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
else
memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
}
if (sub_sw->sub.eth.flags.one_tag)
if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
{
ethernet_vlan_header_t *outer = (void *) (h + 1);
@@ -143,7 +165,7 @@ ethernet_build_rewrite (vnet_main_t * vnm,
outer->type = clib_host_to_net_u16 (type);
}
else if (sub_sw->sub.eth.flags.two_tags)
else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
{
ethernet_vlan_header_t *outer = (void *) (h + 1);
ethernet_vlan_header_t *inner = (void *) (outer + 1);
@@ -174,7 +196,12 @@ ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
adj = adj_get (ai);
if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto)
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
{
default_update_adjacency (vnm, sw_if_index, ai);
}
else if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto)
{
arp_update_adjacency (vnm, sw_if_index, ai);
}
@@ -719,7 +746,8 @@ vnet_delete_sub_interface (u32 sw_if_index)
vnet_interface_main_t *im = &vnm->interface_main;
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
si->type == VNET_SW_INTERFACE_TYPE_P2P)
{
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
u64 sup_and_sub_key =
+16 -1
View File
@@ -40,6 +40,7 @@
#include <vlib/vlib.h>
#include <vnet/pg/pg.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/ethernet/p2p_ethernet.h>
#include <vppinfra/sparse_vec.h>
#include <vnet/l2/l2_bvi.h>
@@ -823,7 +824,21 @@ ethernet_sw_interface_get_config (vnet_main_t * vnm,
// Locate the subint for the given ethernet config
si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->sub.eth.flags.default_sub)
if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
{
p2p_ethernet_main_t *p2pm = &p2p_main;
u32 p2pe_sw_if_index =
p2p_ethernet_lookup (hi->hw_if_index, si->p2p.client_mac);
if (p2pe_sw_if_index == ~0)
{
pool_get (p2pm->p2p_subif_pool, subint);
si->p2p.pool_index = subint - p2pm->p2p_subif_pool;
}
else
subint = vec_elt_at_index (p2pm->p2p_subif_pool, si->p2p.pool_index);
*flags = SUBINT_CONFIG_P2P;
}
else if (si->sub.eth.flags.default_sub)
{
subint = &main_intf->default_subint;
*flags = SUBINT_CONFIG_MATCH_0_TAG |
+1
View File
@@ -18,6 +18,7 @@ define p2p_ethernet_add
u32 client_index;
u32 context;
u32 parent_if_index;
u32 subif_id;
u8 remote_mac[6];
};
+157 -8
View File
@@ -18,12 +18,152 @@
#include <vppinfra/bihash_16_8.h>
#include <vnet/vnet.h>
#include <vnet/ethernet/p2p_ethernet.h>
#include <vnet/l2/l2_input.h>
p2p_ethernet_main_t p2p_main;
static void
create_p2pe_key (p2p_key_t * p2pe_key, u32 parent_if_index, u8 * client_mac)
{
clib_memcpy (p2pe_key->mac, client_mac, 6);
p2pe_key->pad1 = 0;
p2pe_key->hw_if_index = parent_if_index;
p2pe_key->pad2 = 0;
}
u32
p2p_ethernet_lookup (u32 parent_if_index, u8 * client_mac)
{
p2p_ethernet_main_t *p2pm = &p2p_main;
p2p_key_t p2pe_key;
uword *p;
create_p2pe_key (&p2pe_key, parent_if_index, client_mac);
p = hash_get_mem (p2pm->p2p_ethernet_by_key, &p2pe_key);
if (p)
return p[0];
return ~0;
}
int
p2p_ethernet_add_del (vlib_main_t * vm, u32 parent_if_index,
u8 * client_mac, int is_add)
u8 * client_mac, u32 p2pe_subif_id, int is_add,
u32 * p2pe_if_index)
{
return 0;
vnet_main_t *vnm = vnet_get_main ();
p2p_ethernet_main_t *p2pm = &p2p_main;
vnet_interface_main_t *im = &vnm->interface_main;
u32 p2pe_sw_if_index = ~0;
p2pe_sw_if_index = p2p_ethernet_lookup (parent_if_index, client_mac);
if (p2pe_if_index)
*p2pe_if_index = ~0;
if (is_add)
{
if (p2pe_sw_if_index == ~0)
{
vnet_hw_interface_t *hi;
hi = vnet_get_hw_interface (vnm, parent_if_index);
if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
return VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
u64 sup_and_sub_key =
((u64) (hi->sw_if_index) << 32) | (u64) p2pe_subif_id;
uword *p;
p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
if (p)
{
if (CLIB_DEBUG > 0)
clib_warning
("p2p ethernet sub-interface on sw_if_index %d with sub id %d already exists\n",
hi->sw_if_index, p2pe_subif_id);
return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
}
vnet_sw_interface_t template = {
.type = VNET_SW_INTERFACE_TYPE_P2P,
.flood_class = VNET_FLOOD_CLASS_NORMAL,
.sup_sw_if_index = hi->sw_if_index,
.sub.id = p2pe_subif_id
};
clib_memcpy (template.p2p.client_mac, client_mac,
sizeof (template.p2p.client_mac));
if (vnet_create_sw_interface (vnm, &template, &p2pe_sw_if_index))
return VNET_API_ERROR_SUBIF_CREATE_FAILED;
vnet_interface_main_t *im = &vnm->interface_main;
sup_and_sub_key =
((u64) (hi->sw_if_index) << 32) | (u64) p2pe_subif_id;
u64 *kp = clib_mem_alloc (sizeof (*kp));
*kp = sup_and_sub_key;
hash_set (hi->sub_interface_sw_if_index_by_id, p2pe_subif_id,
p2pe_sw_if_index);
hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, p2pe_sw_if_index);
p2p_key_t *p_p2pe_key;
p_p2pe_key = clib_mem_alloc (sizeof (*p_p2pe_key));
create_p2pe_key (p_p2pe_key, parent_if_index, client_mac);
hash_set_mem (p2pm->p2p_ethernet_by_key, p_p2pe_key,
p2pe_sw_if_index);
if (p2pe_if_index)
*p2pe_if_index = p2pe_sw_if_index;
vec_validate (p2pm->p2p_ethernet_by_sw_if_index, parent_if_index);
if (p2pm->p2p_ethernet_by_sw_if_index[parent_if_index] == 0)
{
vnet_feature_enable_disable ("device-input",
"p2p-ethernet-input",
parent_if_index, 1, 0, 0);
/* Set promiscuous mode on the l2 interface */
ethernet_set_flags (vnm, parent_if_index,
ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
}
p2pm->p2p_ethernet_by_sw_if_index[parent_if_index]++;
/* set the interface mode */
set_int_l2_mode (vm, vnm, MODE_L3, p2pe_subif_id, 0, 0, 0, 0);
return 0;
}
return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
}
else
{
if (p2pe_sw_if_index == ~0)
return VNET_API_ERROR_SUBIF_DOESNT_EXIST;
else
{
int rv = 0;
rv = vnet_delete_sub_interface (p2pe_sw_if_index);
if (!rv)
{
vec_validate (p2pm->p2p_ethernet_by_sw_if_index,
parent_if_index);
if (p2pm->p2p_ethernet_by_sw_if_index[parent_if_index] == 1)
{
vnet_feature_enable_disable ("device-input",
"p2p-ethernet-input",
parent_if_index, 0, 0, 0);
/* Disable promiscuous mode on the l2 interface */
ethernet_set_flags (vnm, parent_if_index, 0);
}
p2pm->p2p_ethernet_by_sw_if_index[parent_if_index]--;
/* Remove p2p_ethernet from hash map */
p2p_key_t *p_p2pe_key;
p_p2pe_key = clib_mem_alloc (sizeof (*p_p2pe_key));
create_p2pe_key (p_p2pe_key, parent_if_index, client_mac);
hash_unset_mem (p2pm->p2p_ethernet_by_key, p_p2pe_key);
}
return rv;
}
}
}
static clib_error_t *
@@ -35,6 +175,7 @@ vnet_p2p_ethernet_add_del (vlib_main_t * vm, unformat_input_t * input,
int is_add = 1;
int remote_mac = 0;
u32 hw_if_index = ~0;
u32 sub_id = ~0;
u8 client_mac[6];
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
@@ -44,6 +185,8 @@ vnet_p2p_ethernet_add_del (vlib_main_t * vm, unformat_input_t * input,
;
else if (unformat (input, "%U", unformat_ethernet_address, &client_mac))
remote_mac = 1;
else if (unformat (input, "sub-id %d", &sub_id))
;
else if (unformat (input, "del"))
is_add = 0;
else
@@ -54,9 +197,11 @@ vnet_p2p_ethernet_add_del (vlib_main_t * vm, unformat_input_t * input,
return clib_error_return (0, "Please specify parent interface ...");
if (!remote_mac)
return clib_error_return (0, "Please specify client MAC address ...");
if (sub_id == ~0 && is_add)
return clib_error_return (0, "Please specify sub-interface id ...");
u32 rv;
rv = p2p_ethernet_add_del (vm, hw_if_index, client_mac, is_add);
rv = p2p_ethernet_add_del (vm, hw_if_index, client_mac, sub_id, is_add, 0);
switch (rv)
{
case VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED:
@@ -77,17 +222,21 @@ vnet_p2p_ethernet_add_del (vlib_main_t * vm, unformat_input_t * input,
return 0;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (p2p_ethernet_add_del_command, static) =
{
.path = "p2p_ethernet ",
.function = vnet_p2p_ethernet_add_del,
.short_help = "p2p_ethernet <intfc> <mac-address> [del]",};
/* *INDENT-ON* */
.path = "p2p_ethernet ",.function = vnet_p2p_ethernet_add_del,.short_help =
"p2p_ethernet <intfc> <mac-address> [sub-id <id> | del]",};
static clib_error_t *
p2p_ethernet_init (vlib_main_t * vm)
{
p2p_ethernet_main_t *p2pm = &p2p_main;
p2pm->vlib_main = vm;
p2pm->vnet_main = vnet_get_main ();
p2pm->p2p_ethernet_by_key =
hash_create_mem (0, sizeof (p2p_key_t), sizeof (uword));
return 0;
}
+41 -1
View File
@@ -18,6 +18,46 @@
#include <vnet/vnet.h>
#include <vnet/ethernet/ethernet.h>
int p2p_ethernet_add_del (vlib_main_t * vm, u32 parent_if_index, u8 * client_mac, int is_add);
typedef struct {
/**
* Hash mapping parent sw_if_index and client mac address to p2p_ethernet sub-interface
*/
uword * p2p_ethernet_by_key;
u32 *p2p_ethernet_by_sw_if_index;
// Pool of p2p subifs;
subint_config_t *p2p_subif_pool;
/* convenience */
vlib_main_t * vlib_main;
vnet_main_t * vnet_main;
} p2p_ethernet_main_t;
extern p2p_ethernet_main_t p2p_main;
typedef struct
{
u32 sw_if_index;
u32 p2pe_sw_if_index;
u8 client_mac[6];
} p2p_ethernet_trace_t;
/**
* @brief Key struct for P2P Ethernet
* Key fields: parent sw_if_index and client mac address
* all fields in NET byte order
*/
typedef struct {
u8 mac[6];
u16 pad1; // padding for u64 mac address
u32 hw_if_index;
u32 pad2; // padding for u64
} p2p_key_t;
u32 p2p_ethernet_lookup (u32 parent_sw_if_index, u8* client_mac);
int p2p_ethernet_add_del (vlib_main_t * vm, u32 parent_if_index, u8 * client_mac, u32 sub_id, int is_add, u32 *p2pe_if_index);
#endif /* included_vnet_p2p_ethernet_h */
+12 -3
View File
@@ -51,12 +51,21 @@ vl_api_p2p_ethernet_add_t_handler (vl_api_p2p_ethernet_add_t * mp)
int rv;
u32 parent_if_index = htonl (mp->parent_if_index);
u32 sub_id = htonl (mp->subif_id);
u32 p2pe_if_index;
u8 remote_mac[6];
clib_memcpy (remote_mac, mp->remote_mac, 6);
rv = p2p_ethernet_add_del (vm, parent_if_index, remote_mac, 1);
rv =
p2p_ethernet_add_del (vm, parent_if_index, remote_mac, sub_id, 1,
&p2pe_if_index);
REPLY_MACRO (VL_API_P2P_ETHERNET_ADD_REPLY);
/* *INDENT-OFF* */
REPLY_MACRO2(VL_API_P2P_ETHERNET_ADD_REPLY,
({
rmp->sw_if_index = htonl(p2pe_if_index);
}));
/* *INDENT-ON* */
}
void
@@ -70,7 +79,7 @@ vl_api_p2p_ethernet_del_t_handler (vl_api_p2p_ethernet_del_t * mp)
u8 remote_mac[6];
clib_memcpy (remote_mac, mp->remote_mac, 6);
rv = p2p_ethernet_add_del (vm, parent_if_index, remote_mac, 0);
rv = p2p_ethernet_add_del (vm, parent_if_index, remote_mac, ~0, 0, 0);
REPLY_MACRO (VL_API_P2P_ETHERNET_DEL_REPLY);
}
+247
View File
@@ -0,0 +1,247 @@
/*
* node.c: p2p ethernet vpp node
*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vppinfra/error.h>
#include <vnet/ethernet/p2p_ethernet.h>
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
vlib_node_registration_t p2p_ethernet_input_node;
/* packet trace format function */
u8 *
format_p2p_ethernet_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
p2p_ethernet_trace_t *t = va_arg (*args, p2p_ethernet_trace_t *);
vnet_main_t *vnm = &vnet_main;
s = format (s, "P2P ethernet: %U -> %U",
format_vnet_sw_if_index_name, vnm, t->sw_if_index,
format_vnet_sw_if_index_name, vnm, t->p2pe_sw_if_index);
return s;
}
#define foreach_p2p_ethernet_error \
_(HITS, "P2P ethernet incoming packets processed")
typedef enum
{
#define _(sym,str) P2PE_ERROR_##sym,
foreach_p2p_ethernet_error
#undef _
P2PE_N_ERROR,
} p2p_ethernet_error_t;
static char *p2p_ethernet_error_strings[] = {
#define _(sym,string) string,
foreach_p2p_ethernet_error
#undef _
};
static uword
p2p_ethernet_input_node_fn (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
u32 n_trace = vlib_get_trace_count (vm, node);
u32 n_left_from, *from, *to_next;
u32 next_index;
u32 n_p2p_ethernet_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);
while (n_left_from >= 4 && n_left_to_next >= 2)
{
u32 bi0, bi1;
vlib_buffer_t *b0, *b1;
u32 next0 = 0, next1 = 0;
u32 sw_if_index0, sw_if_index1;
ethernet_header_t *en0, *en1;
u32 rx0, rx1;
bi0 = from[0];
bi1 = from[1];
to_next[0] = bi0;
to_next[1] = bi1;
from += 2;
to_next += 2;
n_left_to_next -= 2;
n_left_from -= 2;
b0 = vlib_get_buffer (vm, bi0);
b1 = vlib_get_buffer (vm, bi1);
en0 = vlib_buffer_get_current (b0);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
en1 = vlib_buffer_get_current (b1);
sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
vnet_feature_next (sw_if_index0, &next0, b0);
vnet_feature_next (sw_if_index1, &next1, b1);
rx0 = p2p_ethernet_lookup (sw_if_index0, en0->src_address);
rx1 = p2p_ethernet_lookup (sw_if_index1, en1->src_address);
if (rx0 != ~0)
{
/* Send pkt to p2p_ethernet RX interface */
vnet_buffer (b0)->sw_if_index[VLIB_RX] = rx0;
n_p2p_ethernet_packets += 1;
if (PREDICT_FALSE (n_trace > 0))
{
p2p_ethernet_trace_t *t0;
vlib_trace_buffer (vm, node, next_index, b0,
1 /* follow_chain */ );
vlib_set_trace_count (vm, node, --n_trace);
t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
t0->sw_if_index = sw_if_index0;
t0->p2pe_sw_if_index = rx0;
}
}
if (rx1 != ~0)
{
/* Send pkt to p2p_ethernet RX interface */
vnet_buffer (b1)->sw_if_index[VLIB_RX] = rx1;
n_p2p_ethernet_packets += 1;
if (PREDICT_FALSE (n_trace > 0))
{
p2p_ethernet_trace_t *t1;
vlib_trace_buffer (vm, node, next_index, b1,
1 /* follow_chain */ );
vlib_set_trace_count (vm, node, --n_trace);
t1 = vlib_add_trace (vm, node, b1, sizeof (*t1));
t1->sw_if_index = sw_if_index1;
t1->p2pe_sw_if_index = rx1;
}
}
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi1, next1);
}
while (n_left_from > 0 && n_left_to_next > 0)
{
u32 bi0;
vlib_buffer_t *b0;
u32 next0 = 0;
u32 sw_if_index0;
ethernet_header_t *en0;
u32 rx0;
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);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
vnet_feature_next (sw_if_index0, &next0, b0);
rx0 = p2p_ethernet_lookup (sw_if_index0, en0->src_address);
if (rx0 != ~0)
{
/* Send pkt to p2p_ethernet RX interface */
vnet_buffer (b0)->sw_if_index[VLIB_RX] = rx0;
n_p2p_ethernet_packets += 1;
if (PREDICT_FALSE (n_trace > 0))
{
p2p_ethernet_trace_t *t0;
vlib_trace_buffer (vm, node, next_index, b0,
1 /* follow_chain */ );
vlib_set_trace_count (vm, node, --n_trace);
t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
t0->sw_if_index = sw_if_index0;
t0->p2pe_sw_if_index = rx0;
}
}
else
{
if (PREDICT_FALSE (n_trace > 0))
{
node->flags |= VLIB_NODE_FLAG_TRACE;
}
}
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
vlib_node_increment_counter (vm, p2p_ethernet_input_node.index,
P2PE_ERROR_HITS, n_p2p_ethernet_packets);
return frame->n_vectors;
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (p2p_ethernet_input_node) = {
.function = p2p_ethernet_input_node_fn,
.name = "p2p-ethernet-input",
.vector_size = sizeof (u32),
.format_trace = format_p2p_ethernet_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(p2p_ethernet_error_strings),
.error_strings = p2p_ethernet_error_strings,
.n_next_nodes = 1,
/* edit / add dispositions here */
.next_nodes = {
[0] = "error-drop",
},
};
/* *INDENT-ON* */
VLIB_NODE_FUNCTION_MULTIARCH (p2p_ethernet_input_node,
p2p_ethernet_input_node_fn)
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+4
View File
@@ -1151,6 +1151,10 @@ vnet_hw_interface_compare (vnet_main_t * vnm,
int
vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
{
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
return 1;
vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
vnet_hw_interface_class_t *hc =
vnet_get_hw_interface_class (vnm, hw->hw_class_index);
+15
View File
@@ -505,6 +505,7 @@ typedef enum
/* A sub-interface. */
VNET_SW_INTERFACE_TYPE_SUB,
VNET_SW_INTERFACE_TYPE_P2P,
} vnet_sw_interface_type_t;
typedef struct
@@ -538,6 +539,17 @@ typedef struct
} eth;
} vnet_sub_interface_t;
typedef struct
{
/*
* Subinterface ID. A number 0-N to uniquely identify
* this subinterface under the main interface
*/
u32 id;
u32 pool_index;
u8 client_mac[6];
} vnet_p2p_sub_interface_t;
typedef enum
{
/* Always flood */
@@ -594,6 +606,9 @@ typedef struct
/* VNET_SW_INTERFACE_TYPE_SUB. */
vnet_sub_interface_t sub;
/* VNET_SW_INTERFACE_TYPE_P2P. */
vnet_p2p_sub_interface_t p2p;
};
vnet_flood_class_t flood_class;
+2 -1
View File
@@ -73,7 +73,8 @@ always_inline vnet_sw_interface_t *
vnet_get_sup_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
{
vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
if (sw->type == VNET_SW_INTERFACE_TYPE_SUB)
if (sw->type == VNET_SW_INTERFACE_TYPE_SUB ||
sw->type == VNET_SW_INTERFACE_TYPE_P2P)
sw = vnet_get_sw_interface (vnm, sw->sup_sw_if_index);
return sw;
}
File diff suppressed because it is too large Load Diff
+25
View File
@@ -601,6 +601,19 @@ class VppPapiProvider(object):
'outer_vlan_id': outer_vlan,
'inner_vlan_id': inner_vlan})
def create_p2pethernet_subif(self, sw_if_index, remote_mac, subif_id):
"""Create p2p ethernet subinterface
:param sw_if_index: main (parent) interface
:param remote_mac: client (remote) mac address
"""
return self.api(
self.papi.p2p_ethernet_add,
{'parent_if_index': sw_if_index,
'remote_mac': remote_mac,
'subif_id': subif_id})
def delete_subif(self, sw_if_index):
"""Delete subinterface
@@ -609,6 +622,18 @@ class VppPapiProvider(object):
return self.api(self.papi.delete_subif,
{'sw_if_index': sw_if_index})
def delete_p2pethernet_subif(self, sw_if_index, remote_mac):
"""Delete p2p ethernet subinterface
:param sw_if_index: main (parent) interface
:param remote_mac: client (remote) mac address
"""
return self.api(
self.papi.p2p_ethernet_del,
{'parent_if_index': sw_if_index,
'remote_mac': remote_mac})
def create_vlan_subif(self, sw_if_index, vlan):
"""
+23
View File
@@ -188,3 +188,26 @@ class VppDot1ADSubint(VppSubInterface):
def remove_dot1_layer(self, packet):
return self.remove_dot1ad_layer(packet, self.outer_vlan,
self.inner_vlan)
class VppP2PSubint(VppSubInterface):
def __init__(self, test, parent, sub_id, remote_mac):
r = test.vapi.create_p2pethernet_subif(parent.sw_if_index,
remote_mac, sub_id)
self._sw_if_index = r.sw_if_index
super(VppP2PSubint, self).__init__(test, parent, sub_id)
def add_dot1_layer(self, packet):
return packet
def remove_dot1_layer(self, packet):
return packet
def create_arp_req(self):
packet = VppPGInterface.create_arp_req(self)
return packet
def create_ndp_req(self):
packet = VppPGInterface.create_ndp_req(self)
return packet