#include <vnet/vxlan/vxlan.h>
#include <vnet/ip/format.h>
+/**
+ * @file
+ * @brief VXLAN.
+ *
+ * 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.
+ */
+
+
vxlan_main_t vxlan_main;
static u8 * format_decap_next (u8 * s, va_list * args)
s = format (s,
"[%d] %U (src) %U (dst) vni %d encap_fib_index %d",
t - ngm->tunnels,
- format_ip46_address, &t->src,
- format_ip46_address, &t->dst,
+ format_ip46_address, &t->src, IP46_TYPE_ANY,
+ format_ip46_address, &t->dst, IP46_TYPE_ANY,
t->vni,
t->encap_fib_index);
s = format (s, " decap_next %U\n", format_decap_next, t->decap_next_index);
int rv;
vxlan4_tunnel_key_t key4;
vxlan6_tunnel_key_t key6;
+ l2output_main_t * l2om = &l2output_main;
if (!a->is_ip6) {
key4.src = a->dst.ip4.as_u32; /* decap src in key is encap dst in config */
key6.src.as_u64[1] = a->dst.ip6.as_u64[1];
key6.vni = clib_host_to_net_u32 (a->vni << 8);
- p = hash_get (vxm->vxlan6_tunnel_by_key, pointer_to_uword(&key6));
+ p = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6);
}
if (a->is_add)
else foreach_copy_ipv6
#undef _
- if (a->is_ip6) {
- /* copy the key */
- t->key6 = key6;
- }
+ /* copy the key */
+ if (a->is_ip6)
+ {
+ t->key6 = clib_mem_alloc (sizeof(vxlan6_tunnel_key_t));
+ clib_memcpy (t->key6, &key6, sizeof(key6));
+ }
+ else
+ {
+ t->key4 = 0; /* not yet used */
+ }
if (!a->is_ip6) t->flags |= VXLAN_TUNNEL_IS_IPV4;
if (!a->is_ip6)
hash_set (vxm->vxlan4_tunnel_by_key, key4.as_u64, t - vxm->tunnels);
else
- hash_set (vxm->vxlan6_tunnel_by_key, pointer_to_uword(&t->key6), t - vxm->tunnels);
+ hash_set_mem (vxm->vxlan6_tunnel_by_key, t->key6, t - vxm->tunnels);
if (vec_len (vxm->free_vxlan_tunnel_hw_if_indices) > 0)
{
l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
l2im->configs[sw_if_index].bd_index = 0;
}
+
+ /*
+ * Directs the l2 output path to work out the interface
+ * output next-arc itself. Needed when recycling a tunnel.
+ */
+ vec_validate_init_empty(l2om->next_nodes.output_node_index_vec,
+ sw_if_index, ~0);
+ l2om->next_nodes.output_node_index_vec[t->sw_if_index]
+ = ~0;
vnet_sw_interface_set_flags (vnm, sw_if_index,
VNET_SW_INTERFACE_FLAG_ADMIN_UP);
if (!a->is_ip6) {
- vec_validate (im4->fib_index_by_sw_if_index, sw_if_index);
- im4->fib_index_by_sw_if_index[sw_if_index] = t->encap_fib_index;
+ vec_validate (im4->fib_index_by_sw_if_index, sw_if_index);
+ im4->fib_index_by_sw_if_index[sw_if_index] = t->encap_fib_index;
+ ip4_sw_interface_enable_disable(sw_if_index, 1);
} else {
vec_validate (im6->fib_index_by_sw_if_index, sw_if_index);
im6->fib_index_by_sw_if_index[sw_if_index] = t->encap_fib_index;
+ ip6_sw_interface_enable_disable(sw_if_index, 1);
}
}
else
vxm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
+ /* Directs the l2 path to turf packets sent to this sw_if_index */
+ l2om->next_nodes.output_node_index_vec[t->sw_if_index]
+ = L2OUTPUT_NEXT_DEL_TUNNEL;
+
if (!a->is_ip6)
- hash_unset (vxm->vxlan4_tunnel_by_key, key4.as_u64);
+ {
+ hash_unset (vxm->vxlan4_tunnel_by_key, key4.as_u64);
+ ip4_sw_interface_enable_disable(sw_if_index, 1);
+ }
else
- hash_unset (vxm->vxlan6_tunnel_by_key, pointer_to_uword(&key6));
-
+ {
+ hash_unset_mem (vxm->vxlan6_tunnel_by_key, t->key6);
+ clib_mem_free (t->key6);
+ ip6_sw_interface_enable_disable(sw_if_index, 1);
+ }
vec_free (t->rewrite);
- if (!a->is_ip6) {
- t->rewrite = vxlan4_dummy_rewrite;
- } else {
- t->rewrite = vxlan6_dummy_rewrite;
- }
pool_put (vxm->tunnels, t);
}
u32 tmp;
int rv;
vnet_vxlan_add_del_tunnel_args_t _a, * a = &_a;
+ u32 sw_if_index;
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
else foreach_copy_ipv6
#undef _
- rv = vnet_vxlan_add_del_tunnel (a, 0 /* hw_if_indexp */);
+ rv = vnet_vxlan_add_del_tunnel (a, &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);
break;
case VNET_API_ERROR_INVALID_DECAP_NEXT:
return clib_error_return (0, "invalid decap-next...");
return 0;
}
+/*?
+ * 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 decap-next l2}
+ * 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 (create_vxlan_tunnel_command, static) = {
.path = "create vxlan tunnel",
.short_help =
"create vxlan tunnel src <local-vtep-addr> dst <remote-vtep-addr> vni <nn>"
- " [encap-vrf-id <nn>] [decap-next [l2|ip4|ip6] [del]\n",
+ " [encap-vrf-id <nn>] [decap-next [l2|ip4|ip6]] [del]",
.function = vxlan_add_del_tunnel_command_fn,
};
+/* *INDENT-ON* */
static clib_error_t *
show_vxlan_tunnel_command_fn (vlib_main_t * vm,
return 0;
}
+/*?
+ * Display all the VXLAN Tunnel entries.
+ *
+ * @cliexpar
+ * Example of how to display the VXLAN Tunnel entries:
+ * @cliexstart{show vxlan tunnel}
+ * [0] 10.0.3.1 (src) 10.0.3.3 (dst) vni 13 encap_fib_index 1 decap_next l2
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
VLIB_CLI_COMMAND (show_vxlan_tunnel_command, static) = {
.path = "show vxlan tunnel",
+ .short_help = "show vxlan tunnel",
.function = show_vxlan_tunnel_command_fn,
};
+/* *INDENT-ON* */
clib_error_t *vxlan_init (vlib_main_t *vm)
{
vxlan_main_t * vxm = &vxlan_main;
- ip4_vxlan_header_t * hdr4;
- ip4_header_t * ip4;
- ip6_vxlan_header_t * hdr6;
- ip6_header_t * ip6;
vxm->vnet_main = vnet_get_main();
vxm->vlib_main = vm;
sizeof(vxlan6_tunnel_key_t),
sizeof(uword));
- /* init dummy rewrite string for deleted vxlan tunnels */
- _vec_len(vxlan4_dummy_rewrite) = sizeof(ip4_vxlan_header_t);
- hdr4 = (ip4_vxlan_header_t *) vxlan4_dummy_rewrite;
- ip4 = &hdr4->ip4;
- /* minimal rewrite setup, see vxlan_rewite() above as reference */
- ip4->ip_version_and_header_length = 0x45;
- ip4->checksum = ip4_header_checksum (ip4);
-
- /* Same again for IPv6 */
- _vec_len(vxlan6_dummy_rewrite) = sizeof(ip6_vxlan_header_t);
- hdr6 = (ip6_vxlan_header_t *) vxlan6_dummy_rewrite;
- ip6 = &hdr6->ip6;
- /* minimal rewrite setup, see vxlan_rewite() above as reference */
- ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(6 << 28);
-
udp_register_dst_port (vm, UDP_DST_PORT_vxlan,
vxlan4_input_node.index, /* is_ip4 */ 1);
udp_register_dst_port (vm, UDP_DST_PORT_vxlan6,