aboutsummaryrefslogtreecommitdiffstats
path: root/vnet/vnet/map
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/map')
-rw-r--r--vnet/vnet/map/map.c218
-rw-r--r--vnet/vnet/map/map.h61
-rw-r--r--vnet/vnet/map/map_dpo.c191
-rw-r--r--vnet/vnet/map/map_dpo.h67
4 files changed, 395 insertions, 142 deletions
diff --git a/vnet/vnet/map/map.c b/vnet/vnet/map/map.c
index 5b5bae54..74a99057 100644
--- a/vnet/vnet/map/map.c
+++ b/vnet/vnet/map/map.c
@@ -15,6 +15,11 @@
* limitations under the License.
*/
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/adj/adj.h>
+#include <vnet/map/map_dpo.h>
+
#include "map.h"
#ifndef __SSE4_2__
@@ -159,15 +164,12 @@ map_create_domain (ip4_address_t * ip4_prefix,
u8 psid_offset,
u8 psid_length, u32 * map_domain_index, u16 mtu, u8 flags)
{
+ u8 suffix_len, suffix_shift;
map_main_t *mm = &map_main;
- ip4_main_t *im4 = &ip4_main;
- ip6_main_t *im6 = &ip6_main;
+ dpo_id_t dpo_v4 = DPO_NULL;
+ dpo_id_t dpo_v6 = DPO_NULL;
+ fib_node_index_t fei;
map_domain_t *d;
- ip_adjacency_t adj;
- ip4_add_del_route_args_t args4;
- ip6_add_del_route_args_t args6;
- u8 suffix_len, suffix_shift;
- uword *p;
/* Sanity check on the src prefix length */
if (flags & MAP_DOMAIN_TRANSLATION)
@@ -236,73 +238,82 @@ map_create_domain (ip4_address_t * ip4_prefix,
d->psid_mask = (1 << d->psid_length) - 1;
d->ea_shift = 64 - ip6_prefix_len - suffix_len - d->psid_length;
- /* Init IP adjacency */
- memset (&adj, 0, sizeof (adj));
- adj.explicit_fib_index = ~0;
- adj.lookup_next_index =
- (d->flags & MAP_DOMAIN_TRANSLATION) ? IP_LOOKUP_NEXT_MAP_T :
- IP_LOOKUP_NEXT_MAP;
- p = (uword *) & adj.rewrite_data[0];
- *p = (uword) (*map_domain_index);
+ /* MAP data-plane object */
+ if (d->flags & MAP_DOMAIN_TRANSLATION)
+ map_t_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
+ else
+ map_dpo_create (DPO_PROTO_IP4, *map_domain_index, &dpo_v4);
+
+ /* Create ip4 route */
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = d->ip4_prefix_len,
+ .fp_addr = {
+ .ip4 = d->ip4_prefix,
+ }
+ ,
+ };
+ fib_table_entry_special_dpo_add (0, &pfx,
+ FIB_SOURCE_MAP,
+ FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
+ dpo_reset (&dpo_v4);
- if (ip4_get_route (im4, 0, 0, (u8 *) ip4_prefix, ip4_prefix_len))
+ /*
+ * Multiple MAP domains may share same source IPv6 TEP.
+ * In this case the route will exist and be MAP sourced.
+ * Find the adj (if any) already contributed and modify it
+ */
+ fib_prefix_t pfx6 = {
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_len = d->ip6_src_len,
+ .fp_addr = {
+ .ip6 = d->ip6_src,
+ }
+ ,
+ };
+ fei = fib_table_lookup_exact_match (0, &pfx6);
+
+ if (FIB_NODE_INDEX_INVALID != fei)
{
- clib_warning ("IPv4 route already defined: %U/%d", format_ip4_address,
- ip4_prefix, ip4_prefix_len);
- pool_put (mm->domains, d);
- return -1;
- }
+ dpo_id_t dpo = DPO_NULL;
- /* Create ip4 adjacency */
- memset (&args4, 0, sizeof (args4));
- args4.table_index_or_table_id = 0;
- args4.flags = IP4_ROUTE_FLAG_ADD;
- args4.dst_address.as_u32 = ip4_prefix->as_u32;
- args4.dst_address_length = ip4_prefix_len;
+ if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_MAP, &dpo))
+ {
+ /*
+ * modify the existing MAP to indicate it's shared
+ * skip to route add.
+ */
+ const dpo_id_t *md_dpo;
+ map_dpo_t *md;
- args4.adj_index = ~0;
- args4.add_adj = &adj;
- args4.n_add_adj = 1;
- ip4_add_del_route (im4, &args4);
+ ASSERT (DPO_LOAD_BALANCE == dpo.dpoi_type);
- /* Multiple MAP domains may share same source IPv6 TEP */
- u32 ai = ip6_get_route (im6, 0, 0, ip6_src, ip6_src_len);
- if (ai > 0)
- {
- ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
- ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
- if (adj6->lookup_next_index != IP_LOOKUP_NEXT_MAP &&
- adj6->lookup_next_index != IP_LOOKUP_NEXT_MAP_T)
- {
- clib_warning ("BR source address already assigned: %U",
- format_ip6_address, ip6_src);
- pool_put (mm->domains, d);
- return -1;
- }
- /* Shared source */
- p = (uword *) & adj6->rewrite_data[0];
- p[0] = ~0;
+ md_dpo = load_balance_get_bucket (dpo.dpoi_index, 0);
+ md = map_dpo_get (md_dpo->dpoi_index);
- /*
- * Add refcount, so we don't accidentially delete the route
- * underneath someone
- */
- p[1]++;
+ md->md_domain = ~0;
+ dpo_copy (&dpo_v6, md_dpo);
+ dpo_reset (&dpo);
+
+ goto route_add;
+ }
}
+
+ if (d->flags & MAP_DOMAIN_TRANSLATION)
+ map_t_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
else
- {
- /* Create ip6 adjacency. */
- memset (&args6, 0, sizeof (args6));
- args6.table_index_or_table_id = 0;
- args6.flags = IP6_ROUTE_FLAG_ADD;
- args6.dst_address.as_u64[0] = ip6_src->as_u64[0];
- args6.dst_address.as_u64[1] = ip6_src->as_u64[1];
- args6.dst_address_length = ip6_src_len;
- args6.adj_index = ~0;
- args6.add_adj = &adj;
- args6.n_add_adj = 1;
- ip6_add_del_route (im6, &args6);
- }
+ map_dpo_create (DPO_PROTO_IP6, *map_domain_index, &dpo_v6);
+
+route_add:
+ /*
+ * Create ip6 route. This is a reference counted add. If the prefix
+ * already exists and is MAP sourced, it is now MAP source n+1 times
+ * and will need to be removed n+1 times.
+ */
+ fib_table_entry_special_dpo_add (0, &pfx6,
+ FIB_SOURCE_MAP,
+ FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v6);
+ dpo_reset (&dpo_v6);
/* Validate packet/byte counters */
map_domain_counter_lock (mm);
@@ -332,12 +343,7 @@ int
map_delete_domain (u32 map_domain_index)
{
map_main_t *mm = &map_main;
- ip4_main_t *im4 = &ip4_main;
- ip6_main_t *im6 = &ip6_main;
map_domain_t *d;
- ip_adjacency_t adj;
- ip4_add_del_route_args_t args4;
- ip6_add_del_route_args_t args6;
if (pool_is_free_index (mm->domains, map_domain_index))
{
@@ -348,47 +354,26 @@ map_delete_domain (u32 map_domain_index)
d = pool_elt_at_index (mm->domains, map_domain_index);
- memset (&adj, 0, sizeof (adj));
- adj.explicit_fib_index = ~0;
- adj.lookup_next_index =
- (d->flags & MAP_DOMAIN_TRANSLATION) ? IP_LOOKUP_NEXT_MAP_T :
- IP_LOOKUP_NEXT_MAP;
-
- /* Delete ip4 adjacency */
- memset (&args4, 0, sizeof (args4));
- args4.table_index_or_table_id = 0;
- args4.flags = IP4_ROUTE_FLAG_DEL;
- args4.dst_address.as_u32 = d->ip4_prefix.as_u32;
- args4.dst_address_length = d->ip4_prefix_len;
- args4.adj_index = 0;
- args4.add_adj = &adj;
- args4.n_add_adj = 0;
- ip4_add_del_route (im4, &args4);
-
- /* Delete ip6 adjacency */
- u32 ai = ip6_get_route (im6, 0, 0, &d->ip6_src, d->ip6_src_len);
- if (ai > 0)
- {
- ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
- ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
-
- uword *p = (uword *) & adj6->rewrite_data[0];
- /* Delete route when no other domains use this source */
- if (p[1] == 0)
- {
- memset (&args6, 0, sizeof (args6));
- args6.table_index_or_table_id = 0;
- args6.flags = IP6_ROUTE_FLAG_DEL;
- args6.dst_address.as_u64[0] = d->ip6_src.as_u64[0];
- args6.dst_address.as_u64[1] = d->ip6_src.as_u64[1];
- args6.dst_address_length = d->ip6_src_len;
- args6.adj_index = 0;
- args6.add_adj = &adj;
- args6.n_add_adj = 0;
- ip6_add_del_route (im6, &args6);
- }
- p[1]--;
- }
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = d->ip4_prefix_len,
+ .fp_addr = {
+ .ip4 = d->ip4_prefix,
+ }
+ ,
+ };
+ fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_MAP);
+
+ fib_prefix_t pfx6 = {
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_len = d->ip6_src_len,
+ .fp_addr = {
+ .ip6 = d->ip6_src,
+ }
+ ,
+ };
+ fib_table_entry_special_remove (0, &pfx6, FIB_SOURCE_MAP);
+
/* Deleting rules */
if (d->rules)
clib_mem_free (d->rules);
@@ -448,17 +433,18 @@ static void
map_pre_resolve (ip4_address_t * ip4, ip6_address_t * ip6)
{
map_main_t *mm = &map_main;
- ip4_main_t *im4 = &ip4_main;
ip6_main_t *im6 = &ip6_main;
if (ip6->as_u64[0] != 0 || ip6->as_u64[1] != 0)
{
- mm->adj6_index = ip6_fib_lookup_with_table (im6, 0, ip6);
+ // 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);
}
if (ip4->as_u32 != 0)
{
- mm->adj4_index = ip4_fib_lookup_with_table (im4, 0, ip4, 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);
}
}
@@ -2156,6 +2142,8 @@ map_init (vlib_main_t * vm)
mm->ip6_reass_fifo_last = MAP_REASS_INDEX_NONE;
map_ip6_reass_reinit (NULL, NULL);
+ map_dpo_module_init ();
+
return 0;
}
diff --git a/vnet/vnet/map/map.h b/vnet/vnet/map/map.h
index fb532291..b76891b6 100644
--- a/vnet/vnet/map/map.h
+++ b/vnet/vnet/map/map.h
@@ -17,6 +17,11 @@
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vlib/vlib.h>
+#include <vnet/fib/fib_types.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/adj/adj.h>
+#include <vnet/map/map_dpo.h>
+#include <vnet/dpo/load_balance.h>
#define MAP_SKIP_IP6_LOOKUP 1
@@ -105,6 +110,9 @@ typedef struct
u8 ip4_prefix_len;
} map_domain_t;
+_Static_assert ((sizeof (map_domain_t) <= CLIB_CACHE_LINE_BYTES),
+ "MAP domain fits in one cacheline");
+
#define MAP_REASS_INDEX_NONE ((u16)0xffff)
/*
@@ -381,16 +389,17 @@ map_get_ip4 (ip6_address_t *addr)
* Get the MAP domain from an IPv4 lookup adjacency.
*/
static_always_inline map_domain_t *
-ip4_map_get_domain (u32 adj_index, u32 *map_domain_index)
+ip4_map_get_domain (u32 mdi,
+ u32 *map_domain_index)
{
map_main_t *mm = &map_main;
- ip_lookup_main_t *lm = &ip4_main.lookup_main;
- ip_adjacency_t *adj = ip_get_adjacency(lm, adj_index);
- ASSERT(adj);
- uword *p = (uword *)adj->rewrite_data;
- ASSERT(p);
- *map_domain_index = p[0];
- return pool_elt_at_index(mm->domains, p[0]);
+ map_dpo_t *md;
+
+ md = map_dpo_get(mdi);
+
+ ASSERT(md);
+ *map_domain_index = md->md_domain;
+ return pool_elt_at_index(mm->domains, *map_domain_index);
}
/*
@@ -399,36 +408,34 @@ ip4_map_get_domain (u32 adj_index, u32 *map_domain_index)
* The IPv4 address is used otherwise.
*/
static_always_inline map_domain_t *
-ip6_map_get_domain (u32 adj_index, ip4_address_t *addr,
+ip6_map_get_domain (u32 mdi, ip4_address_t *addr,
u32 *map_domain_index, u8 *error)
{
map_main_t *mm = &map_main;
- ip4_main_t *im4 = &ip4_main;
- ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
+ map_dpo_t *md;
/*
* Disable direct MAP domain lookup on decap, until the security check is updated to verify IPv4 SA.
* (That's done implicitly when MAP domain is looked up in the IPv4 FIB)
*/
#ifdef MAP_NONSHARED_DOMAIN_ENABLED
- ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
- ip_adjacency_t *adj = ip_get_adjacency(lm6, adj_index);
- ASSERT(adj);
- uword *p = (uword *)adj->rewrite_data;
- ASSERT(p);
- *map_domain_index = p[0];
- if (p[0] != ~0)
- return pool_elt_at_index(mm->domains, p[0]);
-#endif
+ md = map_dpo_get(mdi);
- u32 ai = ip4_fib_lookup_with_table(im4, 0, addr, 0);
- ip_adjacency_t *adj4 = ip_get_adjacency (lm4, ai);
- if (PREDICT_TRUE(adj4->lookup_next_index == IP_LOOKUP_NEXT_MAP ||
- adj4->lookup_next_index == IP_LOOKUP_NEXT_MAP_T)) {
- uword *p = (uword *)adj4->rewrite_data;
- *map_domain_index = p[0];
+ ASSERT(md);
+ *map_domain_index = md->md_domain;
+ if (*map_domain_index != ~0)
return pool_elt_at_index(mm->domains, *map_domain_index);
- }
+#endif
+
+ u32 lbi = ip4_fib_forwarding_lookup(0, addr);
+ const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0);
+ if (PREDICT_TRUE(dpo->dpoi_type == map_dpo_type ||
+ dpo->dpoi_type == map_t_dpo_type))
+ {
+ md = map_dpo_get(dpo->dpoi_index);
+ *map_domain_index = md->md_domain;
+ return pool_elt_at_index(mm->domains, *map_domain_index);
+ }
*error = MAP_ERROR_NO_DOMAIN;
return NULL;
}
diff --git a/vnet/vnet/map/map_dpo.c b/vnet/vnet/map/map_dpo.c
new file mode 100644
index 00000000..df2b5fa4
--- /dev/null
+++ b/vnet/vnet/map/map_dpo.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ip/ip.h>
+#include <vnet/map/map_dpo.h>
+
+/**
+ * pool of all MPLS Label DPOs
+ */
+map_dpo_t *map_dpo_pool;
+
+/**
+ * The register MAP DPO type
+ */
+dpo_type_t map_dpo_type;
+dpo_type_t map_t_dpo_type;
+
+static map_dpo_t *
+map_dpo_alloc (void)
+{
+ map_dpo_t *md;
+
+ pool_get_aligned(map_dpo_pool, md, CLIB_CACHE_LINE_BYTES);
+ memset(md, 0, sizeof(*md));
+
+ return (md);
+}
+
+static index_t
+map_dpo_get_index (map_dpo_t *md)
+{
+ return (md - map_dpo_pool);
+}
+
+void
+map_dpo_create (dpo_proto_t dproto,
+ u32 domain_index,
+ dpo_id_t *dpo)
+{
+ map_dpo_t *md;
+
+ md = map_dpo_alloc();
+ md->md_domain = domain_index;
+ md->md_proto = dproto;
+
+ dpo_set(dpo,
+ map_dpo_type,
+ dproto,
+ map_dpo_get_index(md));
+}
+
+void
+map_t_dpo_create (dpo_proto_t dproto,
+ u32 domain_index,
+ dpo_id_t *dpo)
+{
+ map_dpo_t *md;
+
+ md = map_dpo_alloc();
+ md->md_domain = domain_index;
+ md->md_proto = dproto;
+
+ dpo_set(dpo,
+ map_t_dpo_type,
+ dproto,
+ map_dpo_get_index(md));
+}
+
+
+u8*
+format_map_dpo (u8 *s, va_list *args)
+{
+ index_t index = va_arg (*args, index_t);
+ CLIB_UNUSED(u32 indent) = va_arg (*args, u32);
+ map_dpo_t *md;
+
+ md = map_dpo_get(index);
+
+ return (format(s, "map:[%d]:%U domain:%d",
+ index,
+ format_dpo_proto, md->md_proto,
+ md->md_domain));
+}
+
+u8*
+format_map_t_dpo (u8 *s, va_list *args)
+{
+ index_t index = va_arg (*args, index_t);
+ CLIB_UNUSED(u32 indent) = va_arg (*args, u32);
+ map_dpo_t *md;
+
+ md = map_dpo_get(index);
+
+ return (format(s, "map-t:[%d]:%U domain:%d",
+ index,
+ format_dpo_proto, md->md_proto,
+ md->md_domain));
+}
+
+
+static void
+map_dpo_lock (dpo_id_t *dpo)
+{
+ map_dpo_t *md;
+
+ md = map_dpo_get(dpo->dpoi_index);
+
+ md->md_locks++;
+}
+
+static void
+map_dpo_unlock (dpo_id_t *dpo)
+{
+ map_dpo_t *md;
+
+ md = map_dpo_get(dpo->dpoi_index);
+
+ md->md_locks--;
+
+ if (0 == md->md_locks)
+ {
+ pool_put(map_dpo_pool, md);
+ }
+}
+
+const static dpo_vft_t md_vft = {
+ .dv_lock = map_dpo_lock,
+ .dv_unlock = map_dpo_unlock,
+ .dv_format = format_map_dpo,
+};
+
+const static char* const map_ip4_nodes[] =
+{
+ "ip4-map",
+ NULL,
+};
+const static char* const map_ip6_nodes[] =
+{
+ "ip6-map",
+ NULL,
+};
+
+const static char* const * const map_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = map_ip4_nodes,
+ [DPO_PROTO_IP6] = map_ip6_nodes,
+ [DPO_PROTO_MPLS] = NULL,
+};
+
+const static dpo_vft_t md_t_vft = {
+ .dv_lock = map_dpo_lock,
+ .dv_unlock = map_dpo_unlock,
+ .dv_format = format_map_t_dpo,
+};
+
+const static char* const map_t_ip4_nodes[] =
+{
+ "ip4-map-t",
+ NULL,
+};
+const static char* const map_t_ip6_nodes[] =
+{
+ "ip6-map-t",
+ NULL,
+};
+
+const static char* const * const map_t_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = map_t_ip4_nodes,
+ [DPO_PROTO_IP6] = map_t_ip6_nodes,
+ [DPO_PROTO_MPLS] = NULL,
+};
+
+void
+map_dpo_module_init (void)
+{
+ map_dpo_type = dpo_register_new_type(&md_vft, map_nodes);
+ map_t_dpo_type = dpo_register_new_type(&md_t_vft, map_t_nodes);
+}
diff --git a/vnet/vnet/map/map_dpo.h b/vnet/vnet/map/map_dpo.h
new file mode 100644
index 00000000..be510dba
--- /dev/null
+++ b/vnet/vnet/map/map_dpo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MAP_DPO_H__
+#define __MAP_DPO_H__
+
+#include <vnet/vnet.h>
+#include <vnet/dpo/dpo.h>
+
+/**
+ * A representation of a MAP DPO
+ */
+typedef struct map_dpo_t
+{
+ /**
+ * The dat-plane protocol
+ */
+ dpo_proto_t md_proto;
+
+ /**
+ * the MAP domain index
+ */
+ u32 md_domain;
+
+ /**
+ * Number of locks/users of the label
+ */
+ u16 md_locks;
+} map_dpo_t;
+
+extern void map_dpo_create (dpo_proto_t dproto,
+ u32 domain_index,
+ dpo_id_t *dpo);
+extern void map_t_dpo_create (dpo_proto_t dproto,
+ u32 domain_index,
+ dpo_id_t *dpo);
+
+extern u8* format_map_dpo(u8 *s, va_list *args);
+
+/*
+ * Encapsulation violation for fast data-path access
+ */
+extern map_dpo_t *map_dpo_pool;
+extern dpo_type_t map_dpo_type;
+extern dpo_type_t map_t_dpo_type;
+
+static inline map_dpo_t *
+map_dpo_get (index_t index)
+{
+ return (pool_elt_at_index(map_dpo_pool, index));
+}
+
+extern void map_dpo_module_init(void);
+
+#endif