aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/map
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-02-20 18:23:41 -0800
committerOle Trøan <otroan@employees.org>2017-03-09 13:24:11 +0000
commit8082380922c65702251d5242058f7b5f35011574 (patch)
tree5cc74ecd11ef619c4e1f6cfaf769c1d9fb3fed5f /src/vnet/map
parent37be73693a46b05360483778efee3313a71654f5 (diff)
MAP pre-resolve - use FIB to track pre-resolved next-hop
Change-Id: I9ea16881caf7aee57f0daf4ac2e8b82c672f87e9 Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/map')
-rw-r--r--src/vnet/map/ip4_map.c16
-rw-r--r--src/vnet/map/ip6_map.c16
-rw-r--r--src/vnet/map/map.c172
-rw-r--r--src/vnet/map/map.h41
4 files changed, 190 insertions, 55 deletions
diff --git a/src/vnet/map/ip4_map.c b/src/vnet/map/ip4_map.c
index 9fd10f62eb1..2be9ad37e72 100644
--- a/src/vnet/map/ip4_map.c
+++ b/src/vnet/map/ip4_map.c
@@ -173,18 +173,10 @@ static_always_inline bool
ip4_map_ip6_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
{
#ifdef MAP_SKIP_IP6_LOOKUP
- map_main_t *mm = &map_main;
- u32 adj_index0 = mm->adj6_index;
- if (adj_index0 > 0)
+ if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP6].fei)
{
- ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
- ip_adjacency_t *adj = ip_get_adjacency (lm6, mm->adj6_index);
- if (adj->n_adj > 1)
- {
- u32 hash_c0 = ip4_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT);
- adj_index0 += (hash_c0 & (adj->n_adj - 1));
- }
- vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
+ vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
+ pre_resolved[FIB_PROTOCOL_IP6].dpo.dpoi_index;
return (true);
}
#endif
@@ -773,7 +765,7 @@ VLIB_REGISTER_NODE(ip4_map_node) = {
.next_nodes = {
[IP4_MAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
#ifdef MAP_SKIP_IP6_LOOKUP
- [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-rewrite",
+ [IP4_MAP_NEXT_IP6_REWRITE] = "ip6-load-balance",
#endif
[IP4_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
[IP4_MAP_NEXT_IP6_FRAGMENT] = "ip6-frag",
diff --git a/src/vnet/map/ip6_map.c b/src/vnet/map/ip6_map.c
index d2945059df7..f7eb768fa71 100644
--- a/src/vnet/map/ip6_map.c
+++ b/src/vnet/map/ip6_map.c
@@ -151,18 +151,10 @@ static_always_inline bool
ip6_map_ip4_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
{
#ifdef MAP_SKIP_IP6_LOOKUP
- map_main_t *mm = &map_main;
- u32 adj_index0 = mm->adj4_index;
- if (adj_index0 > 0)
+ if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP4].fei)
{
- ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
- ip_adjacency_t *adj = ip_get_adjacency (lm4, mm->adj4_index);
- if (adj->n_adj > 1)
- {
- u32 hash_c0 = ip4_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT);
- adj_index0 += (hash_c0 & (adj->n_adj - 1));
- }
- vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0;
+ vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
+ pre_resolved[FIB_PROTOCOL_IP4].dpo.dpoi_index;
return (true);
}
#endif
@@ -1195,7 +1187,7 @@ VLIB_REGISTER_NODE(ip6_map_node) = {
.next_nodes = {
[IP6_MAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
#ifdef MAP_SKIP_IP6_LOOKUP
- [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-rewrite",
+ [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-load-balance",
#endif
[IP6_MAP_NEXT_IP6_REASS] = "ip6-map-ip6-reass",
[IP6_MAP_NEXT_IP4_REASS] = "ip6-map-ip4-reass",
diff --git a/src/vnet/map/map.c b/src/vnet/map/map.c
index a2d28118ff4..6823a46e24a 100644
--- a/src/vnet/map/map.c
+++ b/src/vnet/map/map.c
@@ -41,6 +41,7 @@ crc_u32 (u32 data, u32 value)
}
#endif
+
/*
* This code supports the following MAP modes:
*
@@ -437,23 +438,141 @@ map_add_del_psid (u32 map_domain_index, u16 psid, ip6_address_t * tep,
}
#ifdef MAP_SKIP_IP6_LOOKUP
+/**
+ * Pre-resolvd per-protocol global next-hops
+ */
+map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX];
+
static void
-map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6)
+map_pre_resolve_init (map_main_pre_resolved_t * pr)
{
- map_main_t *mm = &map_main;
- ip6_main_t *im6 = &ip6_main;
+ pr->fei = FIB_NODE_INDEX_INVALID;
+ fib_node_init (&pr->node, FIB_NODE_TYPE_MAP_E);
+}
+
+static u8 *
+format_map_pre_resolve (u8 * s, va_list ap)
+{
+ map_main_pre_resolved_t *pr = va_arg (ap, map_main_pre_resolved_t *);
+
+ if (FIB_NODE_INDEX_INVALID != pr->fei)
+ {
+ fib_prefix_t pfx;
+
+ fib_entry_get_prefix (pr->fei, &pfx);
+
+ return (format (s, "%U (%u)",
+ format_ip46_address, &pfx.fp_addr, IP46_TYPE_ANY,
+ pr->dpo.dpoi_index));
+ }
+ else
+ {
+ return (format (s, "un-set"));
+ }
+}
+
+
+/**
+ * Function definition to inform the FIB node that its last lock has gone.
+ */
+static void
+map_last_lock_gone (fib_node_t * node)
+{
+ /*
+ * The MAP is a root of the graph. As such
+ * it never has children and thus is never locked.
+ */
+ ASSERT (0);
+}
+
+static map_main_pre_resolved_t *
+map_from_fib_node (fib_node_t * node)
+{
+#if (CLIB_DEBUG > 0)
+ ASSERT (FIB_NODE_TYPE_MAP_E == node->fn_type);
+#endif
+ return ((map_main_pre_resolved_t *)
+ (((char *) node) -
+ STRUCT_OFFSET_OF (map_main_pre_resolved_t, node)));
+}
+
+static void
+map_stack (map_main_pre_resolved_t * pr)
+{
+ const dpo_id_t *dpo;
- if (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0)
+ dpo = fib_entry_contribute_ip_forwarding (pr->fei);
+
+ dpo_copy (&pr->dpo, dpo);
+}
+
+/**
+ * Function definition to backwalk a FIB node
+ */
+static fib_node_back_walk_rc_t
+map_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
+{
+ map_stack (map_from_fib_node (node));
+
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+}
+
+/**
+ * Function definition to get a FIB node from its index
+ */
+static fib_node_t *
+map_fib_node_get (fib_node_index_t index)
+{
+ return (&pre_resolved[index].node);
+}
+
+/*
+ * Virtual function table registered by MPLS GRE tunnels
+ * for participation in the FIB object graph.
+ */
+const static fib_node_vft_t map_vft = {
+ .fnv_get = map_fib_node_get,
+ .fnv_last_lock = map_last_lock_gone,
+ .fnv_back_walk = map_back_walk,
+};
+
+static void
+map_fib_resolve (map_main_pre_resolved_t * pr,
+ fib_protocol_t proto, u8 len, const ip46_address_t * addr)
+{
+ fib_prefix_t pfx = {
+ .fp_proto = proto,
+ .fp_len = len,
+ .fp_addr = *addr,
+ };
+
+ pr->fei = fib_table_entry_special_add (0, // default fib
+ &pfx,
+ FIB_SOURCE_RR,
+ FIB_ENTRY_FLAG_NONE,
+ ADJ_INDEX_INVALID);
+ pr->sibling = fib_entry_child_add (pr->fei, FIB_NODE_TYPE_MAP_E, proto);
+ map_stack (pr);
+}
+
+static void
+map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6)
+{
+ if (ip6 && (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0))
{
- // FIXME NOT an ADJ
- mm->adj6_index = ip6_fib_table_fwding_lookup (im6, 0, ip6);
- clib_warning ("FIB lookup results in: %u", mm->adj6_index);
+ ip46_address_t addr = {
+ .ip6 = *ip6,
+ };
+ map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP6],
+ FIB_PROTOCOL_IP6, 128, &addr);
}
- if (ip4->as_u32 != 0)
+ if (ip4 && (ip4->as_u32 != 0))
{
- // FIXME NOT an ADJ
- mm->adj4_index = ip4_fib_table_lookup_lb (0, ip4);
- clib_warning ("FIB lookup results in: %u", mm->adj4_index);
+ ip46_address_t addr = {
+ .ip4 = *ip4,
+ };
+ map_fib_resolve (&pre_resolved[FIB_PROTOCOL_IP4],
+ FIB_PROTOCOL_IP4, 32, &addr);
}
}
#endif
@@ -695,9 +814,8 @@ map_pre_resolve_command_fn (vlib_main_t * vm,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
- ip4_address_t ip4nh;
- ip6_address_t ip6nh;
- map_main_t *mm = &map_main;
+ ip4_address_t ip4nh, *p_v4 = NULL;
+ ip6_address_t ip6nh, *p_v6 = NULL;
clib_error_t *error = NULL;
memset (&ip4nh, 0, sizeof (ip4nh));
@@ -710,10 +828,10 @@ map_pre_resolve_command_fn (vlib_main_t * vm,
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "ip4-nh %U", unformat_ip4_address, &ip4nh))
- mm->preresolve_ip4 = ip4nh;
+ p_v4 = &ip4nh;
else
if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh))
- mm->preresolve_ip6 = ip6nh;
+ p_v6 = &ip6nh;
else
{
error = clib_error_return (0, "unknown input `%U'",
@@ -722,7 +840,7 @@ map_pre_resolve_command_fn (vlib_main_t * vm,
}
}
- map_pre_resolve (&ip4nh, &ip6nh);
+ map_pre_resolve (p_v4, p_v6);
done:
unformat_free (line_input);
@@ -1113,9 +1231,10 @@ show_map_stats_command_fn (vlib_main_t * vm, unformat_input_t * input,
#if MAP_SKIP_IP6_LOOKUP
vlib_cli_output (vm,
- "MAP pre-resolve: IP6 next-hop: %U (%u), IP4 next-hop: %U (%u)\n",
- format_ip6_address, &mm->preresolve_ip6, mm->adj6_index,
- format_ip4_address, &mm->preresolve_ip4, mm->adj4_index);
+ "MAP pre-resolve: IP6 next-hop: %U, IP4 next-hop: %U\n",
+ format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP6],
+ format_map_pre_resolve, &pre_resolved[FIB_PROTOCOL_IP4]);
+
#endif
if (mm->tc_copy)
@@ -2180,10 +2299,12 @@ map_init (vlib_main_t * vm)
mm->vlib_main = vm;
#ifdef MAP_SKIP_IP6_LOOKUP
- memset (&mm->preresolve_ip4, 0, sizeof (mm->preresolve_ip4));
- memset (&mm->preresolve_ip6, 0, sizeof (mm->preresolve_ip6));
- mm->adj4_index = 0;
- mm->adj6_index = 0;
+ fib_protocol_t proto;
+
+ FOR_EACH_FIB_PROTOCOL (proto)
+ {
+ map_pre_resolve_init (&pre_resolved[proto]);
+ }
#endif
/* traffic class */
@@ -2238,6 +2359,9 @@ map_init (vlib_main_t * vm)
mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
map_ip6_reass_reinit (NULL, NULL);
+#ifdef MAP_SKIP_IP6_LOOKUP
+ fib_node_register_type (FIB_NODE_TYPE_MAP_E, &map_vft);
+#endif
map_dpo_module_init ();
return 0;
diff --git a/src/vnet/map/map.h b/src/vnet/map/map.h
index f446b739a93..616d42c027a 100644
--- a/src/vnet/map/map.h
+++ b/src/vnet/map/map.h
@@ -198,6 +198,40 @@ typedef struct {
map_ip6_fragment_t fragments[MAP_IP6_REASS_MAX_FRAGMENTS_PER_REASSEMBLY];
} map_ip6_reass_t;
+#ifdef MAP_SKIP_IP6_LOOKUP
+/**
+ * A pre-resolved next-hop
+ */
+typedef struct map_main_pre_resolved_t_
+{
+ /**
+ * Linkage into the FIB graph
+ */
+ fib_node_t node;
+
+ /**
+ * The FIB entry index of the next-hop
+ */
+ fib_node_index_t fei;
+
+ /**
+ * This object sibling index on the FIB entry's child dependency list
+ */
+ u32 sibling;
+
+ /**
+ * The Load-balance object index to use to forward
+ */
+ dpo_id_t dpo;
+} map_main_pre_resolved_t;
+
+/**
+ * Pre-resolved next hops for v4 and v6. Why these are global and not
+ * per-domain is beyond me.
+ */
+extern map_main_pre_resolved_t pre_resolved[FIB_PROTOCOL_MAX];
+#endif
+
typedef struct {
/* pool of MAP domains */
map_domain_t *domains;
@@ -207,13 +241,6 @@ typedef struct {
vlib_combined_counter_main_t *domain_counters;
volatile u32 *counter_lock;
-#ifdef MAP_SKIP_IP6_LOOKUP
- /* pre-presolve */
- u32 adj6_index, adj4_index;
- ip4_address_t preresolve_ip4;
- ip6_address_t preresolve_ip6;
-#endif
-
/* Traffic class: zero, copy (~0) or fixed value */
u8 tc;
bool tc_copy;