diff options
Diffstat (limited to 'vnet/vnet/vxlan/vxlan.c')
-rw-r--r-- | vnet/vnet/vxlan/vxlan.c | 219 |
1 files changed, 117 insertions, 102 deletions
diff --git a/vnet/vnet/vxlan/vxlan.c b/vnet/vnet/vxlan/vxlan.c index d37e9d68..3c6d7bd9 100644 --- a/vnet/vnet/vxlan/vxlan.c +++ b/vnet/vnet/vxlan/vxlan.c @@ -16,6 +16,7 @@ #include <vnet/ip/format.h> #include <vnet/fib/fib_entry.h> #include <vnet/fib/fib_table.h> +#include <vnet/dpo/receive_dpo.h> /** * @file @@ -97,6 +98,19 @@ VNET_HW_INTERFACE_CLASS (vxlan_hw_class) = { .build_rewrite = default_build_rewrite, }; +static void +vxlan_tunnel_restack_dpo(vxlan_tunnel_t * t) +{ + dpo_id_t dpo = DPO_INVALID; + u32 encap_index = ip46_address_is_ip4(&t->dst) ? + vxlan4_encap_node.index : vxlan6_encap_node.index; + fib_forward_chain_type_t forw_type = ip46_address_is_ip4(&t->dst) ? + FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6; + + fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo); + dpo_stack_from_node (encap_index, &t->next_dpo, &dpo); + dpo_reset(&dpo); +} static vxlan_tunnel_t * vxlan_tunnel_from_fib_node (fib_node_t *node) @@ -116,22 +130,7 @@ static fib_node_back_walk_rc_t vxlan_tunnel_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx) { - vxlan_tunnel_t *t = vxlan_tunnel_from_fib_node(node); - dpo_id_t dpo = DPO_INVALID; - - if (ip46_address_is_ip4(&t->dst)) { - fib_entry_contribute_forwarding - (t->fib_entry_index, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo); - dpo_stack_from_node - (vxlan4_encap_node.index, &t->next_dpo, &dpo); - } else { - fib_entry_contribute_forwarding - (t->fib_entry_index, FIB_FORW_CHAIN_TYPE_UNICAST_IP6, &dpo); - dpo_stack_from_node - (vxlan6_encap_node.index, &t->next_dpo, &dpo); - } - dpo_reset(&dpo); - + vxlan_tunnel_restack_dpo(vxlan_tunnel_from_fib_node(node)); return (FIB_NODE_BACK_WALK_CONTINUE); } @@ -175,19 +174,10 @@ const static fib_node_vft_t vxlan_vft = { #define foreach_copy_field \ _(vni) \ -_(encap_fib_index) - -#define foreach_copy_ipv4 { \ - _(src.ip4.as_u32) \ - _(dst.ip4.as_u32) \ -} - -#define foreach_copy_ipv6 { \ - _(src.ip6.as_u64[0]) \ - _(src.ip6.as_u64[1]) \ - _(dst.ip6.as_u64[0]) \ - _(dst.ip6.as_u64[1]) \ -} +_(mcast_sw_if_index) \ +_(encap_fib_index) \ +_(src) \ +_(dst) static int vxlan4_rewrite (vxlan_tunnel_t * t) { @@ -297,8 +287,6 @@ int vnet_vxlan_add_del_tunnel /* copy from arg structure */ #define _(x) t->x = a->x; foreach_copy_field; - if (!is_ip6) foreach_copy_ipv4 - else foreach_copy_ipv6 #undef _ /* copy the key */ @@ -372,66 +360,59 @@ int vnet_vxlan_add_del_tunnel vnet_sw_interface_set_flags (vnm, sw_if_index, VNET_SW_INTERFACE_FLAG_ADMIN_UP); - /* - * source the FIB entry for the tunnel's destination - * and become a child thereof. The tunnel will then get poked - * when the forwarding for the entry updates, and the tunnel can - * re-stack accordingly - */ fib_node_init(&t->node, FIB_NODE_TYPE_VXLAN_TUNNEL); - if (!is_ip6) - { - dpo_id_t dpo = DPO_INVALID; - const fib_prefix_t tun_dst_pfx = - { - .fp_len = 32, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = - { - .ip4 = t->dst.ip4, - } - }; - - t->fib_entry_index = fib_table_entry_special_add - (t->encap_fib_index, &tun_dst_pfx, - FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE, ADJ_INDEX_INVALID); - t->sibling_index = fib_entry_child_add - (t->fib_entry_index, FIB_NODE_TYPE_VXLAN_TUNNEL, t - vxm->tunnels); - fib_entry_contribute_forwarding - (t->fib_entry_index, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo); - dpo_stack_from_node (vxlan4_encap_node.index, &t->next_dpo, &dpo); - dpo_reset(&dpo); - - /* Set vxlan tunnel output node to ip4 version */ - hi->output_node_index = vxlan4_encap_node.index; - } - else - { - dpo_id_t dpo = DPO_INVALID; - const fib_prefix_t tun_dst_pfx = - { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr = - { - .ip6 = t->dst.ip6, - } - }; - - t->fib_entry_index = fib_table_entry_special_add - (t->encap_fib_index, &tun_dst_pfx, - FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE, ADJ_INDEX_INVALID); - t->sibling_index = fib_entry_child_add - (t->fib_entry_index, FIB_NODE_TYPE_VXLAN_TUNNEL, t - vxm->tunnels); - fib_entry_contribute_forwarding - (t->fib_entry_index, FIB_FORW_CHAIN_TYPE_UNICAST_IP6, &dpo); - dpo_stack_from_node - (vxlan6_encap_node.index, &t->next_dpo, &dpo); - dpo_reset(&dpo); - - /* Set vxlan tunnel output node to ip6 version */ - hi->output_node_index = vxlan6_encap_node.index; - } + fib_prefix_t tun_dst_pfx; + u32 encap_index = !is_ip6 ? + vxlan4_encap_node.index : vxlan6_encap_node.index; + vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL; + + fib_prefix_from_ip46_addr(&t->dst, &tun_dst_pfx); + if (ip46_address_is_multicast(&t->dst)) + { + fib_protocol_t fp; + u8 mcast_mac[6]; + if (!is_ip6) { + ip4_multicast_ethernet_address(mcast_mac, &t->dst.ip4); + fp = FIB_PROTOCOL_IP4; + } else { + ip6_multicast_ethernet_address(mcast_mac, t->dst.ip6.as_u32[0]); + fp = FIB_PROTOCOL_IP6; + } + t->mcast_adj_index = adj_rewrite_add_and_lock + (fp, fib_proto_to_link(fp), t->mcast_sw_if_index, mcast_mac); + + flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER; + + /* Stack mcast dst mac addr rewrite on encap */ + dpo_proto_t dproto = fib_proto_to_dpo(fp); + dpo_id_t dpo = DPO_INVALID; + + dpo_set (&dpo, DPO_ADJACENCY, dproto, t->mcast_adj_index); + dpo_stack_from_node (encap_index, &t->next_dpo, &dpo); + dpo_reset(&dpo); + + /* Add local mcast adj. */ + receive_dpo_add_or_lock(dproto, ~0, NULL, &dpo); + t->fib_entry_index = fib_table_entry_special_dpo_add + (t->encap_fib_index, &tun_dst_pfx, FIB_SOURCE_SPECIAL, FIB_ENTRY_FLAG_NONE, &dpo); + dpo_reset(&dpo); + } else { + /* + * source the FIB entry for the tunnel's destination + * and become a child thereof. The tunnel will then get poked + * when the forwarding for the entry updates, and the tunnel can + * re-stack accordingly + */ + t->fib_entry_index = fib_table_entry_special_add + (t->encap_fib_index, &tun_dst_pfx, FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE, ADJ_INDEX_INVALID); + t->sibling_index = fib_entry_child_add + (t->fib_entry_index, FIB_NODE_TYPE_VXLAN_TUNNEL, t - vxm->tunnels); + vxlan_tunnel_restack_dpo(t); + } + /* Set vxlan tunnel output node */ + hi->output_node_index = encap_index; + + vnet_get_sw_interface (vnet_get_main(), sw_if_index)->flood_class = flood_class; } else { @@ -448,8 +429,16 @@ int vnet_vxlan_add_del_tunnel vxm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0; - fib_entry_child_remove(t->fib_entry_index, t->sibling_index); - fib_table_entry_delete_index(t->fib_entry_index, FIB_SOURCE_RR); + if (ip46_address_is_multicast(&t->dst)) + { + adj_unlock(t->mcast_adj_index); + fib_table_entry_delete_index(t->fib_entry_index, FIB_SOURCE_SPECIAL); + } + else + { + fib_entry_child_remove(t->fib_entry_index, t->sibling_index); + fib_table_entry_delete_index(t->fib_entry_index, FIB_SOURCE_RR); + } fib_node_deinit(&t->node); if (!is_ip6) @@ -515,20 +504,26 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { unformat_input_t _line_input, * line_input = &_line_input; - ip46_address_t src, dst; + ip46_address_t src , dst; u8 is_add = 1; u8 src_set = 0; u8 dst_set = 0; + u8 grp_set = 0; u8 ipv4_set = 0; u8 ipv6_set = 0; u32 encap_fib_index = 0; + u32 mcast_sw_if_index = ~0; u32 decap_next_index = ~0; u32 vni = 0; u32 tmp; int rv; vnet_vxlan_add_del_tunnel_args_t _a, * a = &_a; - u32 sw_if_index; - + u32 tunnel_sw_if_index; + + /* Cant "universally zero init" (={0}) due to GCC bug 53119 */ + memset(&src, 0, sizeof src); + memset(&dst, 0, sizeof dst); + /* Get a line of input. */ if (! unformat_user (input, unformat_line_input, line_input)) return 0; @@ -562,6 +557,22 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, dst_set = 1; ipv6_set = 1; } + else if (unformat (line_input, "group %U %U", + unformat_ip4_address, &dst.ip4, + unformat_vnet_sw_interface, + vnet_get_main(), &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "group %U %U", + unformat_ip6_address, &dst.ip6, + unformat_vnet_sw_interface, + vnet_get_main(), &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv6_set = 1; + } else if (unformat (line_input, "encap-vrf-id %d", &tmp)) { if (ipv6_set) @@ -592,11 +603,16 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, if (dst_set == 0) return clib_error_return (0, "tunnel dst address not specified"); + if (grp_set && !ip46_address_is_multicast(&dst)) + return clib_error_return (0, "tunnel group address not multicast"); + + if (grp_set && mcast_sw_if_index == ~0) + return clib_error_return (0, "tunnel nonexistent multicast device"); + if (ipv4_set && ipv6_set) return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); - if ((ipv4_set && memcmp(&src.ip4, &dst.ip4, sizeof(src.ip4)) == 0) || - (ipv6_set && memcmp(&src.ip6, &dst.ip6, sizeof(src.ip6)) == 0)) + if (ip46_address_cmp(&src, &dst) == 0) return clib_error_return (0, "src and dst addresses are identical"); if (vni == 0) @@ -609,18 +625,16 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, #define _(x) a->x = x; foreach_copy_field; - if (ipv4_set) foreach_copy_ipv4 - else foreach_copy_ipv6 #undef _ - rv = vnet_vxlan_add_del_tunnel (a, &sw_if_index); + 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, - vnet_get_main(), sw_if_index); + vnet_get_main(), tunnel_sw_if_index); break; case VNET_API_ERROR_TUNNEL_EXIST: @@ -661,7 +675,8 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (create_vxlan_tunnel_command, static) = { .path = "create vxlan tunnel", .short_help = - "create vxlan tunnel src <local-vtep-addr> dst <remote-vtep-addr> vni <nn>" + "create vxlan tunnel src <local-vtep-addr>" + " {dst <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>" " [encap-vrf-id <nn>]", .function = vxlan_add_del_tunnel_command_fn, }; |