From b02f3b7b8a1c68a974ce43c64b28625b3ca2d4a5 Mon Sep 17 00:00:00 2001 From: Francois Clad Date: Wed, 4 Jul 2018 11:47:21 +0200 Subject: srv6-as: Adding support for L2 traffic Change-Id: I72978c5957cb1acf154c9de7ad153092bac37785 Signed-off-by: Francois Clad --- src/plugins/srv6-as/as.c | 110 ++++++++++++++++++++++-------- src/plugins/srv6-as/as.h | 8 ++- src/plugins/srv6-as/node.c | 163 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 243 insertions(+), 38 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/srv6-as/as.c b/src/plugins/srv6-as/as.c index 5cd5226a462..e771cb485ef 100644 --- a/src/plugins/srv6-as/as.c +++ b/src/plugins/srv6-as/as.c @@ -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", diff --git a/src/plugins/srv6-as/as.h b/src/plugins/srv6-as/as.h index 5cb3e4cb784..0eed05d3156 100644 --- a/src/plugins/srv6-as/as.h +++ b/src/plugins/srv6-as/as.h @@ -23,8 +23,9 @@ #include #include -#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 */ diff --git a/src/plugins/srv6-as/node.c b/src/plugins/srv6-as/node.c index 0e5a16e5e7b..d81a7e88722 100644 --- a/src/plugins/srv6-as/node.c +++ b/src/plugins/srv6-as/node.c @@ -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; + + /* 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; - 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 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 */ -- cgit 1.2.3-korg