diff --git a/src/vnet/interface.h b/src/vnet/interface.h index a1ea2d6..ad0439d 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -658,6 +658,11 @@ void vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add); int vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance); +int +create_ipoe_sub_interfaces (u32 ipoe_sw_if_index, + u32 id, + u32 * sub_sw_if_index); + #endif /* included_vnet_interface_h */ /* diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index b17072a..d07b327 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -733,6 +733,60 @@ done: return error; } +int +create_ipoe_sub_interfaces (u32 ipoe_sw_if_index, + u32 id, + u32 * sub_sw_if_index) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + vnet_sw_interface_t template; + vnet_hw_interface_t *hi; + int rv; + + hi = vnet_get_sup_hw_interface (vnm, ipoe_sw_if_index); + + memset (&template, 0, sizeof (template)); + template.sub.eth.raw_flags = 0; + + uword *p; + vnet_interface_main_t *im = &vnm->interface_main; + u64 sup_and_sub_key = ((u64) ipoe_sw_if_index << 32) | (u64) id; + u64 *kp; + + p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key); + if (p) + { + rv = -1; + goto done; + } + + template.sub.eth.flags.one_tag = 1; + template.sub.eth.outer_vlan_id = (u16)id; + template.sub.eth.flags.exact_match = 1; + + kp = clib_mem_alloc (sizeof (*kp)); + *kp = sup_and_sub_key; + + template.type = VNET_SW_INTERFACE_TYPE_SUB; + template.flood_class = VNET_FLOOD_CLASS_NORMAL; + template.sup_sw_if_index = hi->sw_if_index; + template.sub.id = id; + + error = vnet_create_sw_interface (vnm, &template, sub_sw_if_index); + if (error) + { + rv = -1; + goto done; + } + + hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index); + hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index); + +done: + return rv; +} + /* *INDENT-OFF* */ /*? * Create vlan subinterfaces diff --git a/src/vnet/vxlan/decap.c b/src/vnet/vxlan/decap.c index 514b2c9..5c74707 100644 --- a/src/vnet/vxlan/decap.c +++ b/src/vnet/vxlan/decap.c @@ -83,6 +83,7 @@ vxlan_input (vlib_main_t * vm, u32 pkts_decapsulated = 0; u32 cpu_index = os_get_cpu_number(); u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; + u32 last_tx_index = ~0; if (is_ip4) last_key4.as_u64 = ~0; @@ -115,8 +116,12 @@ vxlan_input (vlib_main_t * vm, vxlan_tunnel_t * t0, * t1, * mt0 = NULL, * mt1 = NULL; vxlan4_tunnel_key_t key4_0, key4_1; vxlan6_tunnel_key_t key6_0, key6_1; + u32 vni0, vni1; u32 error0, error1; + ip46_address_t src0, dst0, src1, dst1; u32 sw_if_index0, sw_if_index1, len0, len1; + u32 ipoe_sub_sw_if_index0, ipoe_sub_sw_if_index1; + u32 tx_sw_if_index0 = ~0, tx_sw_if_index1 = ~0; /* Prefetch next iteration. */ { @@ -199,15 +204,25 @@ vxlan_input (vlib_main_t * vm, p0 = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64); if (PREDICT_FALSE (p0 == NULL)) { - error0 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next0 = VXLAN_INPUT_NEXT_DROP; - goto trace0; + src0.ip4.as_u32 = ip4_0->dst_address.as_u32; + dst0.ip4.as_u32 = ip4_0->src_address.as_u32; + vni0 = vxlan0->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src0, &dst0, + vni0, is_ip4, + &sw_if_index0, + &ipoe_sub_sw_if_index0); + next0 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index0 = last_tx_index = ipoe_sub_sw_if_index0; + goto next_len0; } last_key4.as_u64 = key4_0.as_u64; tunnel_index0 = last_tunnel_index = p0[0]; } else - tunnel_index0 = last_tunnel_index; + { + tunnel_index0 = last_tunnel_index; + tx_sw_if_index0 = last_tx_index; + } t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -248,15 +263,27 @@ vxlan_input (vlib_main_t * vm, p0 = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0); if (PREDICT_FALSE (p0 == NULL)) { - error0 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next0 = VXLAN_INPUT_NEXT_DROP; - goto trace0; + src0.as_u64[0] = ip6_0->dst_address.as_u64[0]; + src0.as_u64[1] = ip6_0->dst_address.as_u64[1]; + dst0.as_u64[0] = ip6_0->src_address.as_u64[0]; + dst0.as_u64[1] = ip6_0->src_address.as_u64[1]; + vni0 = vxlan0->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src0, &dst0, + vni0, is_ip4, + &sw_if_index0, + &ipoe_sub_sw_if_index0); + next0 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index0 = last_tx_index = ipoe_sub_sw_if_index0; + goto next_len0; } clib_memcpy (&last_key6, &key6_0, sizeof(key6_0)); tunnel_index0 = last_tunnel_index = p0[0]; } else - tunnel_index0 = last_tunnel_index; + { + tunnel_index0 = last_tunnel_index; + tx_sw_if_index0 = last_tx_index; + } t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -291,6 +318,9 @@ vxlan_input (vlib_main_t * vm, next0: next0 = t0->decap_next_index; sw_if_index0 = t0->sw_if_index; + + next_len0: + vnet_buffer(b0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; len0 = vlib_buffer_length_in_chain (vm, b0); /* Required to make the l2 tag push / pop code work on l2 subifs */ @@ -351,15 +381,25 @@ vxlan_input (vlib_main_t * vm, p1 = hash_get (vxm->vxlan4_tunnel_by_key, key4_1.as_u64); if (PREDICT_FALSE (p1 == NULL)) { - error1 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next1 = VXLAN_INPUT_NEXT_DROP; - goto trace1; + src1.ip4.as_u32 = ip4_1->dst_address.as_u32; + dst1.ip4.as_u32 = ip4_1->src_address.as_u32; + vni1 = vxlan1->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src1, &dst1, + vni1, is_ip4, + &sw_if_index1, + &ipoe_sub_sw_if_index1); + next1 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index1 = last_tx_index = ipoe_sub_sw_if_index1; + goto next_len1; } last_key4.as_u64 = key4_1.as_u64; tunnel_index1 = last_tunnel_index = p1[0]; } else - tunnel_index1 = last_tunnel_index; + { + tunnel_index1 = last_tunnel_index; + tx_sw_if_index1 = last_tx_index; + } t1 = pool_elt_at_index (vxm->tunnels, tunnel_index1); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -401,16 +441,28 @@ vxlan_input (vlib_main_t * vm, if (PREDICT_FALSE (p1 == NULL)) { - error1 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next1 = VXLAN_INPUT_NEXT_DROP; - goto trace1; + src1.as_u64[0] = ip6_1->dst_address.as_u64[0]; + src1.as_u64[1] = ip6_1->dst_address.as_u64[1]; + dst1.as_u64[0] = ip6_1->src_address.as_u64[0]; + dst1.as_u64[1] = ip6_1->src_address.as_u64[1]; + vni1 = vxlan1->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src1, &dst1, + vni1, is_ip4, + &sw_if_index1, + &ipoe_sub_sw_if_index1); + next1 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index1 = last_tx_index = ipoe_sub_sw_if_index1; + goto next_len1; } clib_memcpy (&last_key6, &key6_1, sizeof(key6_1)); tunnel_index1 = last_tunnel_index = p1[0]; } else - tunnel_index1 = last_tunnel_index; + { + tunnel_index1 = last_tunnel_index; + tx_sw_if_index1 = last_tx_index; + } t1 = pool_elt_at_index (vxm->tunnels, tunnel_index1); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -445,6 +497,9 @@ vxlan_input (vlib_main_t * vm, next1: next1 = t1->decap_next_index; sw_if_index1 = t1->sw_if_index; + + next_len1: + vnet_buffer(b1)->sw_if_index[VLIB_TX] = tx_sw_if_index1; len1 = vlib_buffer_length_in_chain (vm, b1); /* Required to make the l2 tag push / pop code work on l2 subifs */ @@ -506,8 +561,11 @@ vxlan_input (vlib_main_t * vm, vxlan_tunnel_t * t0, * mt0 = NULL; vxlan4_tunnel_key_t key4_0; vxlan6_tunnel_key_t key6_0; + u32 vni0; u32 error0; - u32 sw_if_index0, len0; + ip46_address_t src0, dst0; + u32 sw_if_index0, len0, ipoe_sub_sw_if_index0; + u32 tx_sw_if_index0 = ~0; bi0 = from[0]; to_next[0] = bi0; @@ -559,15 +617,25 @@ vxlan_input (vlib_main_t * vm, p0 = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64); if (PREDICT_FALSE (p0 == NULL)) { - error0 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next0 = VXLAN_INPUT_NEXT_DROP; - goto trace00; + src0.ip4.as_u32 = ip4_0->dst_address.as_u32; + dst0.ip4.as_u32 = ip4_0->src_address.as_u32; + vni0 = vxlan0->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src0, &dst0, + vni0, is_ip4, + &sw_if_index0, + &ipoe_sub_sw_if_index0); + next0 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index0 = last_tx_index = ipoe_sub_sw_if_index0; + goto next_len00; } last_key4.as_u64 = key4_0.as_u64; tunnel_index0 = last_tunnel_index = p0[0]; } else - tunnel_index0 = last_tunnel_index; + { + tunnel_index0 = last_tunnel_index; + tx_sw_if_index0 = last_tx_index; + } t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -608,15 +676,27 @@ vxlan_input (vlib_main_t * vm, p0 = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0); if (PREDICT_FALSE (p0 == NULL)) { - error0 = VXLAN_ERROR_NO_SUCH_TUNNEL; - next0 = VXLAN_INPUT_NEXT_DROP; - goto trace00; + src0.as_u64[0] = ip6_0->dst_address.as_u64[0]; + src0.as_u64[1] = ip6_0->dst_address.as_u64[1]; + dst0.as_u64[0] = ip6_0->src_address.as_u64[0]; + dst0.as_u64[1] = ip6_0->src_address.as_u64[1]; + vni0 = vxlan0->vni_reserved; + vxlan_add_del_tunnel_slowpath(&src0, &dst0, + vni0, is_ip4, + &sw_if_index0, + &ipoe_sub_sw_if_index0); + next0 = VXLAN_INPUT_NEXT_L2_INPUT; + tx_sw_if_index0 = last_tx_index = ipoe_sub_sw_if_index0; + goto next_len00; } clib_memcpy (&last_key6, &key6_0, sizeof(key6_0)); tunnel_index0 = last_tunnel_index = p0[0]; } else - tunnel_index0 = last_tunnel_index; + { + tunnel_index0 = last_tunnel_index; + tx_sw_if_index0 = last_tx_index; + } t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0); /* Validate VXLAN tunnel encap-fib index agaist packet */ @@ -651,6 +731,9 @@ vxlan_input (vlib_main_t * vm, next00: next0 = t0->decap_next_index; sw_if_index0 = t0->sw_if_index; + + next_len00: + vnet_buffer(b0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; len0 = vlib_buffer_length_in_chain (vm, b0); /* Required to make the l2 tag push / pop code work on l2 subifs */ diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index c8a050d..b3c927b 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include /** @@ -359,7 +361,128 @@ fib_ip_proto(bool is_ip6) return (is_ip6) ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4; } -int vnet_vxlan_add_del_tunnel +int +vxlan_add_del_tunnel_slowpath (ip46_address_t * src, + ip46_address_t * dst, + u32 vni, + u32 is_ip4, + u32 * vxlan_sw_if_index, + u32 * ipoe_sub_sw_if_index) +{ + vxlan_main_t * vxm = &vxlan_main; + vlib_main_t * vm = vxm->vlib_main; + vnet_main_t * vnm = vxm->vnet_main; + u32 encap_fib_index = 0, flags = 0; + u32 decap_next_index = VXLAN_INPUT_NEXT_L2_INPUT; + int rv; + vnet_vxlan_add_del_tunnel_args_t _a, * a = &_a; + + /* Cant "universally zero init" (={0}) due to GCC bug 53119 */ + memset (a, 0, sizeof (*a)); + + a->is_add = 1; + a->is_ip6 = (is_ip4? 0 : 1); + a->decap_next_index = decap_next_index; + a->encap_fib_index = encap_fib_index; + a->mcast_sw_if_index = ~0; + a->vni = clib_net_to_host_u32(vni) >> 8; + if(is_ip4) { + a->src.ip4.as_u32 = src->ip4.as_u32; + a->dst.ip4.as_u32 = dst->ip4.as_u32; + } + else { + a->src.ip6 = src->ip6; + a->dst.ip6 = dst->ip6; + } + + rv = vnet_vxlan_add_del_tunnel (a, vxlan_sw_if_index); + + rv = create_ipoe_sub_interfaces(vxm->ipoe_sw_if_index, + a->vni, ipoe_sub_sw_if_index); + + flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP; + vnet_sw_interface_set_flags (vnm, *ipoe_sub_sw_if_index, flags); + + + /* set the interface mode */ + rv = set_int_l2_mode(vm, vnm, MODE_L2_XC, + *vxlan_sw_if_index, 0, 0, 0, *ipoe_sub_sw_if_index); + + rv = set_int_l2_mode(vm, vnm, MODE_L2_XC, + *ipoe_sub_sw_if_index, 0, 0, 0, *vxlan_sw_if_index); + + rv = l2vtr_configure (vm, vnm, *ipoe_sub_sw_if_index, + L2_VTR_POP_1, 0, 0, 0); + + return rv; +} + +static clib_error_t * +ipoe_add_del_interface_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vxlan_main_t * vxm = &vxlan_main; + vnet_main_t * vnm = vxm->vnet_main; + clib_error_t *error = 0; + u32 sw_if_index, is_del; + + sw_if_index = ~0; + is_del = 0; + + if (unformat (input, "del")) + is_del = 1; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + if(!is_del) + { + vxm->ipoe_sw_if_index = sw_if_index; + } + else + { + vxm->ipoe_sw_if_index = ~0; + } + +done: + return error; +} + +/*? + * Add or delete a VXLAN Tunnel. + * + * VXLAN provides the features needed to allow L2 bridge domains (BDs) + * to span multiple servers. This is done by building an L2 overlay on + * top of an L3 network underlay using VXLAN tunnels. + * + * This makes it possible for servers to be co-located in the same data + * center or be separated geographically as long as they are reachable + * through the underlay L3 network. + * + * You can refer to this kind of L2 overlay bridge domain as a VXLAN + * (Virtual eXtensible VLAN) segment. + * + * @cliexpar + * Example of how to create a VXLAN Tunnel: + * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 encap-vrf-id 7} + * Example of how to delete a VXLAN Tunnel: + * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 del} + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_ipoe_interface_command, static) = { + .path = "set ipoe interface", + .short_help = + "set ipoe interface [del]", + .function = ipoe_add_del_interface_command_fn, +}; +/* *INDENT-ON* */ + +int vnet_vxlan_add_del_tunnel (vnet_vxlan_add_del_tunnel_args_t *a, u32 * sw_if_indexp) { vxlan_main_t * vxm = &vxlan_main; @@ -378,14 +501,14 @@ int vnet_vxlan_add_del_tunnel key4.src = a->dst.ip4.as_u32; /* decap src in key is encap dst in config */ key4.vni = clib_host_to_net_u32 (a->vni << 8); p = hash_get (vxm->vxlan4_tunnel_by_key, key4.as_u64); - } - else + } + else { key6.src = a->dst.ip6; key6.vni = clib_host_to_net_u32 (a->vni << 8); p = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6); } - + if (a->is_add) { l2input_main_t * l2im = &l2input_main; @@ -402,7 +525,7 @@ int vnet_vxlan_add_del_tunnel pool_get_aligned (vxm->tunnels, t, CLIB_CACHE_LINE_BYTES); memset (t, 0, sizeof (*t)); - + /* copy from arg structure */ #define _(x) t->x = a->x; foreach_copy_field; @@ -428,7 +551,7 @@ int vnet_vxlan_add_del_tunnel hw_if_index = vxm->free_vxlan_tunnel_hw_if_indices [vec_len (vxm->free_vxlan_tunnel_hw_if_indices)-1]; _vec_len (vxm->free_vxlan_tunnel_hw_if_indices) -= 1; - + hi = vnet_get_hw_interface (vnm, hw_if_index); hi->dev_instance = t - vxm->tunnels; hi->hw_instance = hi->dev_instance; @@ -436,25 +559,25 @@ int vnet_vxlan_add_del_tunnel /* clear old stats of freed tunnel before reuse */ sw_if_index = hi->sw_if_index; vnet_interface_counter_lock(im); - vlib_zero_combined_counter + vlib_zero_combined_counter (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX], sw_if_index); - vlib_zero_combined_counter + vlib_zero_combined_counter (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX], sw_if_index); - vlib_zero_simple_counter + vlib_zero_simple_counter (&im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP], sw_if_index); vnet_interface_counter_unlock(im); } - else + else { hw_if_index = vnet_register_interface (vnm, vxlan_device_class.index, t - vxm->tunnels, vxlan_hw_class.index, t - vxm->tunnels); hi = vnet_get_hw_interface (vnm, hw_if_index); } - + t->hw_if_index = hw_if_index; t->sw_if_index = sw_if_index = hi->sw_if_index; - + vec_validate_init_empty (vxm->tunnel_index_by_sw_if_index, sw_if_index, ~0); vxm->tunnel_index_by_sw_if_index[sw_if_index] = t - vxm->tunnels; @@ -462,10 +585,10 @@ int vnet_vxlan_add_del_tunnel vec_validate (l2im->configs, sw_if_index); l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP; l2im->configs[sw_if_index].bd_index = 0; - + vnet_sw_interface_t * si = vnet_get_sw_interface (vnm, sw_if_index); si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN; - vnet_sw_interface_set_flags (vnm, sw_if_index, + vnet_sw_interface_set_flags (vnm, sw_if_index, VNET_SW_INTERFACE_FLAG_ADMIN_UP); fib_node_init(&t->node, FIB_NODE_TYPE_VXLAN_TUNNEL); @@ -490,7 +613,7 @@ int vnet_vxlan_add_del_tunnel t->sibling_index = fib_entry_child_add (t->fib_entry_index, FIB_NODE_TYPE_VXLAN_TUNNEL, t - vxm->tunnels); vxlan_tunnel_restack_dpo(t); - } + } else { /* Multicast tunnel - @@ -691,7 +814,7 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, dst_set = 1; ipv4_set = 1; } - else if (unformat (line_input, "src %U", + else if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6)) { src_set = 1; @@ -728,18 +851,18 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, goto done; } } - else if (unformat (line_input, "decap-next %U", unformat_decap_next, + else if (unformat (line_input, "decap-next %U", unformat_decap_next, &decap_next_index, ipv4_set)) ; else if (unformat (line_input, "vni %d", &vni)) { - if (vni >> 24) + if (vni >> 24) { error = clib_error_return (0, "vni %d out of range", vni); goto done; } } - else + else { error = clib_error_return (0, "parse error: '%U'", format_unformat_error, line_input); @@ -809,14 +932,14 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, #define _(x) a->x = x; foreach_copy_field; #undef _ - + rv = vnet_vxlan_add_del_tunnel (a, &tunnel_sw_if_index); switch(rv) { case 0: if (is_add) - vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, + vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), tunnel_sw_if_index); break; diff --git a/src/vnet/vxlan/vxlan.h b/src/vnet/vxlan/vxlan.h index dca1cd1..1080cc9 100644 --- a/src/vnet/vxlan/vxlan.h +++ b/src/vnet/vxlan/vxlan.h @@ -153,6 +153,8 @@ typedef struct { /* Mapping from sw_if_index to tunnel index */ u32 * tunnel_index_by_sw_if_index; + u32 ipoe_sw_if_index; + /* convenience */ vlib_main_t * vlib_main; vnet_main_t * vnet_main; @@ -185,4 +187,13 @@ int vnet_vxlan_add_del_tunnel void vnet_int_vxlan_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable); + +int +vxlan_add_del_tunnel_slowpath (ip46_address_t * src, + ip46_address_t * dst, + u32 vni, + u32 is_ip4, + u32 * vxlan_sw_if_index, + u32 * ipoe_sub_sw_if_index); + #endif /* included_vnet_vxlan_h */