diff options
author | Pavel Kotucek <pkotucek@cisco.com> | 2017-06-20 14:00:26 +0200 |
---|---|---|
committer | John Lo <loj@cisco.com> | 2017-08-01 14:44:13 +0000 |
commit | 15ac81c16fba83033090299413a3a2dbb848a0f9 (patch) | |
tree | ca9617e0faa21847be31e47c0c65ffc0cacf47eb /src/vnet | |
parent | 5b311202b82a827c712d2cb7604c56049266adc9 (diff) |
P2P Ethernet
Change-Id: Idb97e573961b3bc2acdeef77582314590795f8c3
Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/api_errno.h | 3 | ||||
-rw-r--r-- | src/vnet/devices/devices.c | 6 | ||||
-rw-r--r-- | src/vnet/ethernet/ethernet.h | 1 | ||||
-rw-r--r-- | src/vnet/ethernet/interface.c | 54 | ||||
-rwxr-xr-x | src/vnet/ethernet/node.c | 17 | ||||
-rw-r--r-- | src/vnet/ethernet/p2p_ethernet.api | 1 | ||||
-rw-r--r-- | src/vnet/ethernet/p2p_ethernet.c | 165 | ||||
-rw-r--r-- | src/vnet/ethernet/p2p_ethernet.h | 42 | ||||
-rw-r--r-- | src/vnet/ethernet/p2p_ethernet_api.c | 17 | ||||
-rw-r--r-- | src/vnet/ethernet/p2p_ethernet_input.c | 247 | ||||
-rw-r--r-- | src/vnet/interface.c | 4 | ||||
-rw-r--r-- | src/vnet/interface.h | 15 | ||||
-rw-r--r-- | src/vnet/interface_funcs.h | 3 |
13 files changed, 546 insertions, 29 deletions
diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index b22bb3a879f..747c65e7fb5 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -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 { diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index f64c6e0dea5..2eb8e30e076 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -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", diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index d9ab8c10508..9ca256c94ce 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -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; diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c index 9ac30bc6652..3e78a49d62b 100644 --- a/src/vnet/ethernet/interface.c +++ b/src/vnet/ethernet/interface.c @@ -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 = diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index 421d501adda..f216216d3d7 100755 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -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 | diff --git a/src/vnet/ethernet/p2p_ethernet.api b/src/vnet/ethernet/p2p_ethernet.api index 72a734237d5..8fb66376522 100644 --- a/src/vnet/ethernet/p2p_ethernet.api +++ b/src/vnet/ethernet/p2p_ethernet.api @@ -18,6 +18,7 @@ define p2p_ethernet_add u32 client_index; u32 context; u32 parent_if_index; + u32 subif_id; u8 remote_mac[6]; }; diff --git a/src/vnet/ethernet/p2p_ethernet.c b/src/vnet/ethernet/p2p_ethernet.c index 3c077318b7b..e3f667b5ffe 100644 --- a/src/vnet/ethernet/p2p_ethernet.c +++ b/src/vnet/ethernet/p2p_ethernet.c @@ -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; } diff --git a/src/vnet/ethernet/p2p_ethernet.h b/src/vnet/ethernet/p2p_ethernet.h index 31b93d829fb..bb1e2896bc2 100644 --- a/src/vnet/ethernet/p2p_ethernet.h +++ b/src/vnet/ethernet/p2p_ethernet.h @@ -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 */ diff --git a/src/vnet/ethernet/p2p_ethernet_api.c b/src/vnet/ethernet/p2p_ethernet_api.c index 1d9eaeb0286..f2c730b4d25 100644 --- a/src/vnet/ethernet/p2p_ethernet_api.c +++ b/src/vnet/ethernet/p2p_ethernet_api.c @@ -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); - - REPLY_MACRO (VL_API_P2P_ETHERNET_ADD_REPLY); + rv = + p2p_ethernet_add_del (vm, parent_if_index, remote_mac, sub_id, 1, + &p2pe_if_index); + + /* *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); } diff --git a/src/vnet/ethernet/p2p_ethernet_input.c b/src/vnet/ethernet/p2p_ethernet_input.c new file mode 100644 index 00000000000..a58b832af14 --- /dev/null +++ b/src/vnet/ethernet/p2p_ethernet_input.c @@ -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: + */ diff --git a/src/vnet/interface.c b/src/vnet/interface.c index dad1f315620..721259a7d04 100644 --- a/src/vnet/interface.c +++ b/src/vnet/interface.c @@ -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); diff --git a/src/vnet/interface.h b/src/vnet/interface.h index fb75ff349b9..5ca489db32d 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -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; diff --git a/src/vnet/interface_funcs.h b/src/vnet/interface_funcs.h index 26eef9b9d87..142bef57465 100644 --- a/src/vnet/interface_funcs.h +++ b/src/vnet/interface_funcs.h @@ -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; } |