vlib_get_combined_counter(&adjacency_counters, adj_index, &counts);
s = format (s, "\n counts:[%Ld:%Ld]", counts.packets, counts.bytes);
s = format (s, "\n locks:%d", adj->ia_node.fn_locks);
- s = format (s, " node:[%d]:%U",
- adj->rewrite_header.node_index,
- format_vlib_node_name, vlib_get_main(),
- adj->rewrite_header.node_index);
- s = format (s, " next:[%d]:%U",
- adj->rewrite_header.next_index,
- format_vlib_next_node_name,
- vlib_get_main(),
- adj->rewrite_header.node_index,
- adj->rewrite_header.next_index);
s = format(s, "\n children:\n ");
s = fib_node_children_format(adj->ia_node.fn_children, s);
}
sibling_index);
}
+/*
+ * Context for the walk to update the cached feture flags.
+ */
+typedef struct adj_feature_update_t_
+{
+ u8 arc;
+ u8 enable;
+} adj_feature_update_ctx_t;
+
+static adj_walk_rc_t
+adj_feature_update_walk_cb (adj_index_t ai,
+ void *arg)
+{
+ adj_feature_update_ctx_t *ctx = arg;
+ ip_adjacency_t *adj;
+
+ adj = adj_get(ai);
+
+ /*
+ * this ugly mess matches the feature arc that is changing with affected
+ * adjacencies
+ */
+ if (((ctx->arc == ip6_main.lookup_main.output_feature_arc_index) &&
+ (VNET_LINK_IP6 == adj->ia_link)) ||
+ ((ctx->arc == ip4_main.lookup_main.output_feature_arc_index) &&
+ (VNET_LINK_IP4 == adj->ia_link)) ||
+ ((ctx->arc == mpls_main.output_feature_arc_index) &&
+ (VNET_LINK_MPLS == adj->ia_link)))
+ {
+ if (ctx->enable)
+ adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES;
+ else
+ adj->rewrite_header.flags &= ~VNET_REWRITE_HAS_FEATURES;
+ }
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+void
+adj_feature_update (u32 sw_if_index,
+ u8 arc_index,
+ u8 is_enable)
+{
+ /*
+ * Walk all the adjacencies on the interface to update the cached
+ * 'has-features' flag
+ */
+ adj_feature_update_ctx_t ctx = {
+ .arc = arc_index,
+ .enable = is_enable,
+ };
+ adj_walk (sw_if_index, adj_feature_update_walk_cb, &ctx);
+}
+
+/**
+ * @brief Walk the Adjacencies on a given interface
+ */
+void
+adj_walk (u32 sw_if_index,
+ adj_walk_cb_t cb,
+ void *ctx)
+{
+ /*
+ * walk all the neighbor adjacencies
+ */
+ fib_protocol_t proto;
+
+ FOR_EACH_FIB_IP_PROTOCOL(proto)
+ {
+ adj_nbr_walk(sw_if_index, proto, cb, ctx);
+ }
+}
+
/**
* @brief Return the link type of the adjacency
*/
*/
extern const u8* adj_get_rewrite (adj_index_t ai);
+/**
+ * @brief Notify the adjacency subsystem that the features settings for
+ * an interface have changed
+ */
+extern void adj_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable);
+
/**
* @brief
* The global adjacnecy pool. Exposed for fast/inline data-plane access
{
index_t index = va_arg(*ap, index_t);
CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
- vnet_main_t * vnm = vnet_get_main();
ip_adjacency_t * adj = adj_get(index);
s = format(s, "%U-mcast: ",
format_fib_protocol, adj->ia_nh_proto);
s = format (s, "%U",
format_vnet_rewrite,
- vnm->vlib_main, &adj->rewrite_header,
- sizeof (adj->rewrite_data), 0);
+ &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
return (s);
}
{
index_t index = va_arg(*ap, index_t);
u32 indent = va_arg(*ap, u32);
- vnet_main_t * vnm = vnet_get_main();
ip_adjacency_t * adj = adj_get(index);
s = format (s, "%U", format_vnet_link, adj->ia_link);
format_ip46_address, &adj->sub_type.nbr.next_hop);
s = format (s, " %U",
format_vnet_rewrite,
- vnm->vlib_main, &adj->rewrite_header,
- sizeof (adj->rewrite_data), indent);
+ &adj->rewrite_header, sizeof (adj->rewrite_data), indent);
s = format (s, "\n%Ustacked-on:\n%U%U",
format_white_space, indent,
format_white_space, indent+2,
vnet_rewrite_clear_data_internal(&adj->rewrite_header,
sizeof(adj->rewrite_data));
}
- adj->rewrite_header.node_index = this_node;
adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(),
this_node,
next_node);
{
index_t index = va_arg(*ap, index_t);
CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
- vnet_main_t * vnm = vnet_get_main();
ip_adjacency_t * adj = adj_get(index);
s = format (s, "%U", format_vnet_link, adj->ia_link);
adj_proto_to_46(adj->ia_nh_proto));
s = format (s, "%U",
format_vnet_rewrite,
- vnm->vlib_main, &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
+ &adj->rewrite_header, sizeof (adj->rewrite_data), 0);
return (s);
}
*/
#include <vnet/feature/feature.h>
+#include <vnet/adj/adj.h>
vnet_feature_main_t feature_main;
fm->sw_if_index_has_features[arc_index] =
clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
(feature_count > 0));
+ adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
return 0;
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
- vnet_main_t *vnm = vnet_get_main ();
uword indent = format_get_indent (s);
s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
s = format (s, "\n%U%U",
format_white_space, indent,
format_ip_adjacency_packet_data,
- vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
+ t->dpo_index, t->packet_data, sizeof (t->packet_data));
return s;
}
tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
{
tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index1, &next1, p1);
+ if (PREDICT_FALSE
+ (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index1, &next1, p1);
}
/* Guess we are only writing on simple Ethernet header. */
adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
}
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
- vnet_main_t *vnm = vnet_get_main ();
uword indent = format_get_indent (s);
s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
s = format (s, "\n%U%U",
format_white_space, indent,
format_ip_adjacency_packet_data,
- vnm, t->adj_index, t->packet_data, sizeof (t->packet_data));
+ t->adj_index, t->packet_data, sizeof (t->packet_data));
return s;
}
vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
{
vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
next1 = adj1[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index1, &next1, p1);
+ if (PREDICT_FALSE
+ (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index1, &next1, p1);
}
/* Guess we are only writing on simple Ethernet header. */
vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
- vnet_feature_arc_start (lm->output_feature_arc_index,
- tx_sw_if_index0, &next0, p0);
+ if (PREDICT_FALSE
+ (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (lm->output_feature_arc_index,
+ tx_sw_if_index0, &next0, p0);
}
if (is_midchain)
u8 *
format_ip_adjacency_packet_data (u8 * s, va_list * args)
{
- vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
u32 adj_index = va_arg (*args, u32);
u8 *packet_data = va_arg (*args, u8 *);
u32 n_packet_data_bytes = va_arg (*args, u32);
switch (adj->lookup_next_index)
{
case IP_LOOKUP_NEXT_REWRITE:
- s = format (s, "%U",
- format_vnet_rewrite_header,
- vnm->vlib_main, &adj->rewrite_header, packet_data,
- n_packet_data_bytes);
+ case IP_LOOKUP_NEXT_MCAST:
+ s =
+ format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
break;
default:
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *);
- vnet_main_t * vnm = vnet_get_main();
uword indent = format_get_indent (s);
s = format (s, "adj-idx %d : %U flow hash: 0x%08x",
s = format (s, "\n%U%U",
format_white_space, indent,
format_ip_adjacency_packet_data,
- vnm, t->adj_index,
- t->packet_data, sizeof (t->packet_data));
+ t->adj_index, t->packet_data, sizeof (t->packet_data));
return s;
}
u32 n_left_from, next_index, * from, * to_next, cpu_index;
vlib_node_runtime_t * error_node;
u32 n_left_to_next;
+ mpls_main_t *mm;
cpu_index = os_get_cpu_number();
error_node = vlib_node_get_runtime (vm, mpls_output_node.index);
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
next_index = node->cached_next_index;
+ mm = &mpls_main;
while (n_left_from > 0)
{
next0 = adj0[0].rewrite_header.next_index;
error0 = IP4_ERROR_NONE;
- if (is_midchain)
- {
- adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
- }
+ if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (mm->output_feature_arc_index,
+ adj0[0].rewrite_header.sw_if_index,
+ &next0, p0);
}
else
{
next1 = adj1[0].rewrite_header.next_index;
error1 = IP4_ERROR_NONE;
- if (is_midchain)
- {
- adj1->sub_type.midchain.fixup_func(vm, adj1, p1);
- }
+ if (PREDICT_FALSE(adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (mm->output_feature_arc_index,
+ adj1[0].rewrite_header.sw_if_index,
+ &next1, p1);
}
else
{
error1 = IP4_ERROR_MTU_EXCEEDED;
next1 = MPLS_OUTPUT_NEXT_DROP;
}
+ if (is_midchain)
+ {
+ adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
+ adj1->sub_type.midchain.fixup_func(vm, adj1, p1);
+ }
p0->error = error_node->errors[error0];
p1->error = error_node->errors[error1];
next0 = adj0[0].rewrite_header.next_index;
error0 = IP4_ERROR_NONE;
- if (is_midchain)
- {
- adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
- }
+ if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
+ vnet_feature_arc_start (mm->output_feature_arc_index,
+ adj0[0].rewrite_header.sw_if_index,
+ &next0, p0);
}
else
{
error0 = IP4_ERROR_MTU_EXCEEDED;
next0 = MPLS_OUTPUT_NEXT_DROP;
}
- p0->error = error_node->errors[error0];
+ if (is_midchain)
+ {
+ adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
+ }
+
+ p0->error = error_node->errors[error0];
from += 1;
n_left_from -= 1;
u8 *
format_vnet_rewrite (u8 * s, va_list * args)
{
- vlib_main_t *vm = va_arg (*args, vlib_main_t *);
vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *);
u32 max_data_bytes = va_arg (*args, u32);
CLIB_UNUSED (uword indent) = va_arg (*args, u32);
vnet_main_t *vnm = vnet_get_main ();
- vlib_node_t *next;
-
- next = vlib_get_next_node (vm, rw->node_index, rw->next_index);
if (rw->sw_if_index != ~0)
{
else
s = format (s, "DELETED");
}
- else
- s = format (s, "%v: ", next->name);
/* Format rewrite string. */
if (rw->data_bytes > 0)
s = format (s, "%U",
- next->format_buffer ? next->format_buffer : format_hex_bytes,
+ format_hex_bytes,
rw->data + max_data_bytes - rw->data_bytes, rw->data_bytes);
return s;
}
-u8 *
-format_vnet_rewrite_header (u8 * s, va_list * args)
-{
- vlib_main_t *vm = va_arg (*args, vlib_main_t *);
- vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *);
- u8 *packet_data = va_arg (*args, u8 *);
- u32 packet_data_bytes = va_arg (*args, u32);
- vlib_node_t *next;
-
- next = vlib_get_next_node (vm, rw->node_index, rw->next_index);
-
- /* Format rewrite string. */
- s = format (s, "%U",
- next->format_buffer ? next->format_buffer : format_hex_bytes,
- packet_data, packet_data_bytes);
-
- return s;
-}
-
-uword
-unformat_vnet_rewrite (unformat_input_t * input, va_list * args)
-{
- vlib_main_t *vm = va_arg (*args, vlib_main_t *);
- vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *);
- u32 max_data_bytes = va_arg (*args, u32);
- vnet_main_t *vnm = vnet_get_main ();
- vlib_node_t *next;
- u32 next_index, sw_if_index, max_packet_bytes, error;
- u8 *rw_data;
-
- rw_data = 0;
- sw_if_index = ~0;
- max_packet_bytes = ~0;
- error = 1;
-
- /* Parse sw interface. */
- if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
- {
- vnet_hw_interface_t *hi;
-
- hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
-
- next_index = hi->output_node_index;
- max_packet_bytes = hi->max_l3_packet_bytes[VLIB_RX];
- }
-
- else if (unformat (input, "%U", unformat_vlib_node, vm, &next_index))
- ;
-
- else
- goto done;
-
- next = vlib_get_node (vm, next_index);
-
- if (next->unformat_buffer
- && unformat_user (input, next->unformat_buffer, &rw_data))
- ;
-
- else if (unformat_user (input, unformat_hex_string, &rw_data)
- || unformat (input, "0x%U", unformat_hex_string, &rw_data))
- ;
-
- else
- goto done;
-
- /* Re-write does not fit. */
- if (vec_len (rw_data) >= max_data_bytes)
- goto done;
-
- {
- u32 tmp;
-
- if (unformat (input, "mtu %d", &tmp)
- && tmp < (1 << BITS (rw->max_l3_packet_bytes)))
- max_packet_bytes = tmp;
- }
-
- error = 0;
- rw->sw_if_index = sw_if_index;
- rw->max_l3_packet_bytes = max_packet_bytes;
- rw->next_index = vlib_node_add_next (vm, rw->node_index, next_index);
- vnet_rewrite_set_data_internal (rw, max_data_bytes, rw_data,
- vec_len (rw_data));
-
-done:
- vec_free (rw_data);
- return error == 0;
-}
-
u32
vnet_tx_node_index_for_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
{
u32 this_node, u32 next_node, vnet_rewrite_header_t * rw)
{
rw->sw_if_index = sw_if_index;
- rw->node_index = this_node;
rw->next_index = vlib_node_add_next (vnm->vlib_main, this_node, next_node);
rw->max_l3_packet_bytes =
vnet_sw_interface_get_mtu (vnm, sw_if_index, VLIB_TX);
* ipX-forward, this will be interpreted as a FIB number.
*/
rw->sw_if_index = tx_sw_if_index;
- rw->node_index = rewrite_node_index;
rw->next_index = vlib_node_add_next (vnm->vlib_main, rewrite_node_index,
post_rewrite_node_index);
rw->max_l3_packet_bytes = (u16) ~ 0; /* we can't know at this point */
u8 *p;
/* It is up to user to fill these in. */
- rw->node_index = ~0;
rw->next_index = ~0;
unserialize_integer (m, &rw->sw_if_index, sizeof (rw->sw_if_index));
/* Consider using vector types for speed? */
typedef uword vnet_rewrite_data_t;
+/**
+ * Flags associated with the rewrite/adjacency
+ */
+typedef enum vnet_rewrite_flags_t_
+{
+ /**
+ * This adjacency/interface has output features configured
+ */
+ VNET_REWRITE_HAS_FEATURES = (1 << 0),
+} __attribute__ ((packed)) vnet_rewrite_flags_t;
+
/* *INDENT-OFF* */
typedef CLIB_PACKED (struct {
/* Interface to mark re-written packets with. */
u32 sw_if_index;
- /* Packet processing node where rewrite happens. */
- u32 node_index;
-
/* Next node to feed after packet rewrite is done. */
u16 next_index;
Used for MTU check after packet rewrite. */
u16 max_l3_packet_bytes;
+ u16 unused1;
+ u8 unused2;
+
+ vnet_rewrite_flags_t flags;
+
/* When dynamically writing a multicast destination L2 addresss
* this is the offset within the address to start writing n
* bytes of the IP mcast address */
}) vnet_rewrite_header_t;
/* *INDENT-ON* */
+/**
+ * At 16 bytes of rewrite herader we have enought space left for a IPv6
+ * (40 bytes) + LISP-GPE (8 bytes) in the cache line
+ */
+STATIC_ASSERT (sizeof (vnet_rewrite_header_t) <= 16,
+ "Rewrite header too big");
+
/*
Helper macro for declaring rewrite string w/ given max-size.
void vnet_update_adjacency_for_sw_interface (struct vnet_main_t *vnm,
u32 sw_if_index, u32 ai);
-/* Parser for unformat header & rewrite string. */
-unformat_function_t unformat_vnet_rewrite;
-
format_function_t format_vnet_rewrite;
-format_function_t format_vnet_rewrite_header;
serialize_function_t serialize_vnet_rewrite, unserialize_vnet_rewrite;