#include <vnet/ip/format.h>
#include <vnet/fib/ip4_fib.h>
#include <vnet/adj/adj_midchain.h>
+#include <vnet/adj/adj_nbr.h>
#include <vnet/mpls/mpls.h>
static inline u64
format_gre_tunnel (u8 * s, va_list * args)
{
gre_tunnel_t * t = va_arg (*args, gre_tunnel_t *);
- int detail = va_arg (*args, int);
gre_main_t * gm = &gre_main;
s = format (s,
format_ip4_address, &t->tunnel_dst,
(t->teb ? "teb" : "ip"),
t->outer_fib_index);
- if (detail)
- {
- s = format (s, "\n fib-entry:%d adj-ip4:%d adj-ip6:%d adj-mpls:%d",
- t->fib_entry_index,
- t->adj_index[FIB_LINK_IP4],
- t->adj_index[FIB_LINK_IP6],
- t->adj_index[FIB_LINK_MPLS]);
- }
return s;
}
* 'stack' (resolve the recursion for) the tunnel's midchain adjacency
*/
void
-gre_tunnel_stack (gre_tunnel_t *gt)
+gre_tunnel_stack (adj_index_t ai)
{
- fib_link_t linkt;
+ gre_main_t * gm = &gre_main;
+ ip_adjacency_t *adj;
+ gre_tunnel_t *gt;
+ u32 sw_if_index;
+
+ adj = adj_get(ai);
+ sw_if_index = adj->rewrite_header.sw_if_index;
+
+ if ((vec_len(gm->tunnel_index_by_sw_if_index) < sw_if_index) ||
+ (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
+ return;
+
+ gt = pool_elt_at_index(gm->tunnels,
+ gm->tunnel_index_by_sw_if_index[sw_if_index]);
/*
* find the adjacency that is contributed by the FIB entry
* that this tunnel resovles via, and use it as the next adj
* in the midchain
*/
- FOR_EACH_FIB_LINK(linkt)
+ if (vnet_hw_interface_get_flags(vnet_get_main(),
+ gt->hw_if_index) &
+ VNET_HW_INTERFACE_FLAG_LINK_UP)
{
- if (ADJ_INDEX_INVALID != gt->adj_index[linkt])
- {
- if (vnet_hw_interface_get_flags(vnet_get_main(),
- gt->hw_if_index) &
- VNET_HW_INTERFACE_FLAG_LINK_UP)
- {
- adj_nbr_midchain_stack(
- gt->adj_index[linkt],
- fib_entry_contribute_ip_forwarding(gt->fib_entry_index));
- }
- else
- {
- adj_nbr_midchain_unstack(gt->adj_index[linkt]);
- }
- }
+ adj_nbr_midchain_stack(
+ ai,
+ fib_entry_contribute_ip_forwarding(gt->fib_entry_index));
+ }
+ else
+ {
+ adj_nbr_midchain_unstack(ai);
+ }
+}
+
+/**
+ * @brief Call back when restacking all adjacencies on a GRE interface
+ */
+static adj_walk_rc_t
+gre_adj_walk_cb (adj_index_t ai,
+ void *ctx)
+{
+ gre_tunnel_stack(ai);
+
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+static void
+gre_tunnel_restack (gre_tunnel_t *gt)
+{
+ fib_protocol_t proto;
+
+ /*
+ * walk all the adjacencies on th GRE interface and restack them
+ */
+ FOR_EACH_FIB_IP_PROTOCOL(proto)
+ {
+ adj_nbr_walk(gt->sw_if_index,
+ proto,
+ gre_adj_walk_cb,
+ NULL);
}
}
*/
static fib_node_back_walk_rc_t
gre_tunnel_back_walk (fib_node_t *node,
- fib_node_back_walk_ctx_t *ctx)
+ fib_node_back_walk_ctx_t *ctx)
{
- gre_tunnel_stack(gre_tunnel_from_fib_node(node));
+ gre_tunnel_restack(gre_tunnel_from_fib_node(node));
return (FIB_NODE_BACK_WALK_CONTINUE);
}
.fnv_back_walk = gre_tunnel_back_walk,
};
-static int
-gre_proto_from_fib_link (fib_link_t link)
-{
- switch (link)
- {
- case FIB_LINK_IP4:
- return (GRE_PROTOCOL_ip4);
- case FIB_LINK_IP6:
- return (GRE_PROTOCOL_ip6);
- case FIB_LINK_MPLS:
- return (GRE_PROTOCOL_mpls_unicast);
- case FIB_LINK_ETHERNET:
- return (GRE_PROTOCOL_teb);
- }
- ASSERT(0);
- return (GRE_PROTOCOL_ip4);
-}
-
-static u8 *
-gre_rewrite (gre_tunnel_t * t,
- fib_link_t link)
-{
- ip4_and_gre_header_t * h0;
- u8 * rewrite_data = 0;
-
- vec_validate_init_empty (rewrite_data, sizeof (*h0) - 1, 0);
-
- h0 = (ip4_and_gre_header_t *) rewrite_data;
-
- h0->gre.protocol = clib_host_to_net_u16(gre_proto_from_fib_link(link));
-
- h0->ip4.ip_version_and_header_length = 0x45;
- h0->ip4.ttl = 254;
- h0->ip4.protocol = IP_PROTOCOL_GRE;
- /* $$$ fixup ip4 header length and checksum after-the-fact */
- h0->ip4.src_address.as_u32 = t->tunnel_src.as_u32;
- h0->ip4.dst_address.as_u32 = t->tunnel_dst.as_u32;
- h0->ip4.checksum = ip4_header_checksum (&h0->ip4);
-
- return (rewrite_data);
-}
-
-static void
-gre_fixup (vlib_main_t *vm,
- ip_adjacency_t *adj,
- vlib_buffer_t *b0)
-{
- ip4_header_t * ip0;
-
- ip0 = vlib_buffer_get_current (b0);
-
- /* Fixup the checksum and len fields in the GRE tunnel encap
- * that was applied at the midchain node */
- ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- ip0->checksum = ip4_header_checksum (ip0);
-}
-
static int
vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
u32 * sw_if_indexp)
u32 outer_fib_index;
u8 address[6];
clib_error_t *error;
- fib_link_t linkt;
- u8 *rewrite;
outer_fib_index = ip4_fib_index_from_table_id(a->outer_fib_id);
pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
memset (t, 0, sizeof (*t));
fib_node_init(&t->node, FIB_NODE_TYPE_GRE_TUNNEL);
- FOR_EACH_FIB_LINK(linkt)
- {
- t->adj_index[linkt] = ADJ_INDEX_INVALID;
- }
if (vec_len (gm->free_gre_tunnel_hw_if_indices) > 0) {
vnet_interface_main_t * im = &vnm->interface_main;
address[3] = 0xd0;
address[4] = t - gm->tunnels;
- error = ethernet_register_interface
- (vnm,
- gre_l2_device_class.index, t - gm->tunnels, address, &hw_if_index,
- 0);
+ error = ethernet_register_interface(vnm,
+ gre_device_class.index,
+ t - gm->tunnels, address,
+ &hw_if_index,
+ 0);
if (error)
{
hi->tx_node_index,
"adj-l2-midchain");
} else {
- hw_if_index = vnet_register_interface
- (vnm, gre_device_class.index, t - gm->tunnels,
- gre_hw_interface_class.index,
- t - gm->tunnels);
+ hw_if_index = vnet_register_interface(vnm,
+ gre_device_class.index,
+ t - gm->tunnels,
+ gre_hw_interface_class.index,
+ t - gm->tunnels);
}
hi = vnet_get_hw_interface (vnm, hw_if_index);
sw_if_index = hi->sw_if_index;
FIB_NODE_TYPE_GRE_TUNNEL,
t - gm->tunnels);
- /*
- * create and update the midchain adj this tunnel sources.
- * We could be smarter here and trigger this on an interface proto enable,
- * like we do for MPLS.
- */
+ clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
+ clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
+
if (t->teb)
{
- t->adj_index[FIB_LINK_ETHERNET] = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
- FIB_LINK_ETHERNET,
- &zero_addr,
- sw_if_index);
-
- rewrite = gre_rewrite(t, FIB_LINK_ETHERNET);
- adj_nbr_midchain_update_rewrite(t->adj_index[FIB_LINK_ETHERNET],
- gre_fixup,
- ADJ_MIDCHAIN_FLAG_NO_COUNT,
- rewrite);
- vec_free(rewrite);
- }
- else
- {
- FOR_EACH_FIB_IP_LINK (linkt)
- {
- t->adj_index[linkt] = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
- linkt,
- &zero_addr,
- sw_if_index);
-
- rewrite = gre_rewrite(t, linkt);
- adj_nbr_midchain_update_rewrite(t->adj_index[linkt],
- gre_fixup,
- ADJ_MIDCHAIN_FLAG_NONE,
- rewrite);
- vec_free(rewrite);
- }
- }
-
- t->adj_index[FIB_LINK_MPLS] = ADJ_INDEX_INVALID;
+ t->l2_adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+ FIB_LINK_ETHERNET,
+ &zero_addr,
+ sw_if_index);
- clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
- clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
- gre_tunnel_stack(t);
+ gre_update_adj(vnm, t->sw_if_index, t->l2_adj_index);
+ }
if (sw_if_indexp)
*sw_if_indexp = sw_if_index;
gre_main_t * gm = &gre_main;
vnet_main_t * vnm = gm->vnet_main;
gre_tunnel_t * t;
- fib_link_t linkt;
u32 sw_if_index;
t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id);
fib_table_entry_delete_index(t->fib_entry_index,
FIB_SOURCE_RR);
- FOR_EACH_FIB_LINK(linkt)
- {
- adj_unlock(t->adj_index[linkt]);
- }
-
gre_tunnel_db_remove(t);
fib_node_deinit(&t->node);
pool_put (gm->tunnels, t);
return (vnet_gre_tunnel_delete(a, sw_if_indexp));
}
-static void
-gre_sw_interface_mpls_state_change (u32 sw_if_index,
- u32 is_enable)
+clib_error_t *
+gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
{
- gre_main_t *gm = &gre_main;
+ gre_main_t * gm = &gre_main;
+ vnet_hw_interface_t * hi;
gre_tunnel_t *t;
- u8 *rewrite;
+ u32 ti;
- if ((vec_len(gm->tunnel_index_by_sw_if_index) < sw_if_index) ||
- (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
- return;
+ hi = vnet_get_hw_interface (vnm, hw_if_index);
- t = pool_elt_at_index(gm->tunnels,
- gm->tunnel_index_by_sw_if_index[sw_if_index]);
+ if (NULL == gm->tunnel_index_by_sw_if_index ||
+ hi->sw_if_index >= vec_len(gm->tunnel_index_by_sw_if_index))
+ return (NULL);
- if (is_enable)
- {
- t->adj_index[FIB_LINK_MPLS] =
- adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
- FIB_LINK_MPLS,
- &zero_addr,
- sw_if_index);
-
- rewrite = gre_rewrite(t, FIB_LINK_MPLS);
- adj_nbr_midchain_update_rewrite(t->adj_index[FIB_LINK_MPLS],
- gre_fixup,
- ADJ_MIDCHAIN_FLAG_NONE,
- rewrite);
- vec_free(rewrite);
- }
+ ti = gm->tunnel_index_by_sw_if_index[hi->sw_if_index];
+
+ if (~0 == ti)
+ /* not one of ours */
+ return (NULL);
+
+ t = pool_elt_at_index(gm->tunnels, ti);
+
+ if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+ vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
else
- {
- adj_unlock(t->adj_index[FIB_LINK_MPLS]);
- t->adj_index[FIB_LINK_MPLS] = ADJ_INDEX_INVALID;
- }
+ vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
- gre_tunnel_stack(t);
+ gre_tunnel_restack(t);
+
+ return /* no error */ 0;
}
static clib_error_t *
{
pool_foreach (t, gm->tunnels,
({
- vlib_cli_output (vm, "%U", format_gre_tunnel, t, 0);
+ vlib_cli_output (vm, "%U", format_gre_tunnel, t);
}));
}
else
{
t = pool_elt_at_index(gm->tunnels, ti);
- vlib_cli_output (vm, "%U", format_gre_tunnel, t, 1);
+ vlib_cli_output (vm, "%U", format_gre_tunnel, t);
}
return 0;
/* force inclusion from application's main.c */
clib_error_t *gre_interface_init (vlib_main_t *vm)
{
- vec_add1(mpls_main.mpls_interface_state_change_callbacks,
- gre_sw_interface_mpls_state_change);
-
fib_node_register_type(FIB_NODE_TYPE_GRE_TUNNEL, &gre_vft);
return 0;