diff options
Diffstat (limited to 'vnet/vnet/map')
-rw-r--r-- | vnet/vnet/map/map.c | 218 | ||||
-rw-r--r-- | vnet/vnet/map/map.h | 61 | ||||
-rw-r--r-- | vnet/vnet/map/map_dpo.c | 191 | ||||
-rw-r--r-- | vnet/vnet/map/map_dpo.h | 67 |
4 files changed, 395 insertions, 142 deletions
diff --git a/vnet/vnet/map/map.c b/vnet/vnet/map/map.c index 5b5bae54720..74a99057c90 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 fb532291f8a..b76891b69b3 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 00000000000..df2b5fa4197 --- /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 00000000000..be510dbaea6 --- /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 |