A Protocol Independent Hierarchical FIB (VPP-352)

Main Enhancements:
 - Protocol Independent FIB API
 - Hierarchical FIB entries. Dynamic recursive route resolution.
 - Extranet Support.
 - Integration of IP and MPLS forwarding.
 - Separation of FIB and Adjacency databases.
 - Data-Plane Object forwarding model.

Change-Id: I52dc815c0d0aa8b493e3cf6b978568f3cc82296c
Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
2016-08-25 15:29:12 +01:00
committed by Damjan Marion
parent 60537f3d83
commit 0bfe5d8c79
197 changed files with 40417 additions and 11972 deletions
+2 -2
View File
@@ -59,12 +59,12 @@ test-driver
# cscope and ctags
/cscope.*
/tags
ID
TAGS
# ggtags
GPATH
GRTAGS
GTAGS
TAGS
# Generated documentation
/build-root/docs
/build-root/.doxygen-bootstrap.ok
File diff suppressed because it is too large Load Diff
+22 -5
View File
@@ -18,6 +18,7 @@
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/fib/fib_node.h>
#include <vppinfra/bihash_24_8.h>
#include <vppinfra/bihash_template.h>
@@ -59,17 +60,32 @@ typedef enum {
} ila_direction_t;
typedef struct {
/**
* Fib Node base class
*/
fib_node_t ila_fib_node;
ila_type_t type;
ip6_address_t sir_address;
ip6_address_t ila_address;
u32 ila_adj_index;
ip6_address_t next_hop;
ila_csum_mode_t csum_mode;
ila_direction_t dir;
} ila_entry_t;
typedef struct {
u32 entry_index;
} ila_adj_data_t;
/**
* The FIB entry index for the next-hop
*/
fib_node_index_t next_hop_fib_entry_index;
/**
* The child index on the FIB entry
*/
u32 next_hop_child_index;
/**
* The next DPO in the grpah to follow
*/
dpo_id_t ila_dpo;
} ila_entry_t;
typedef struct {
ila_entry_t *entries; //Pool of ILA entries
@@ -87,6 +103,7 @@ typedef struct {
typedef struct {
ila_type_t type;
ip6_address_t sir_address;
ip6_address_t next_hop_address;
u64 locator;
u32 vnid;
u32 local_adj_index;
+99 -99
View File
@@ -537,54 +537,54 @@ int lb_vip_del_ass(u32 vip_index, ip46_address_t *addresses, u32 n)
int lb_as_lookup_bypass(u32 vip_index, ip46_address_t *address, u8 is_disable)
{
lb_get_writer_lock();
lb_main_t *lbm = &lb_main;
u32 as_index;
lb_as_t *as;
lb_vip_t *vip;
/* lb_get_writer_lock(); */
/* lb_main_t *lbm = &lb_main; */
/* u32 as_index; */
/* lb_as_t *as; */
/* lb_vip_t *vip; */
if (!(vip = lb_vip_get_by_index(vip_index)) ||
lb_as_find_index_vip(vip, address, &as_index)) {
lb_put_writer_lock();
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
/* if (!(vip = lb_vip_get_by_index(vip_index)) || */
/* lb_as_find_index_vip(vip, address, &as_index)) { */
/* lb_put_writer_lock(); */
/* return VNET_API_ERROR_NO_SUCH_ENTRY; */
/* } */
as = &lbm->ass[as_index];
/* as = &lbm->ass[as_index]; */
if (is_disable) {
as->adj_index = ~0;
} else if (lb_vip_is_gre4(vip)) {
uword *p = ip4_get_route (&ip4_main, 0, 0, as->address.ip4.as_u8, 32);
if (p == 0) {
lb_put_writer_lock();
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
u32 ai = (u32)p[0];
ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
ip_adjacency_t *adj4 = ip_get_adjacency (lm4, ai);
if (adj4->lookup_next_index != IP_LOOKUP_NEXT_REWRITE) {
lb_put_writer_lock();
return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
}
/* if (is_disable) { */
/* as->adj_index = ~0; */
/* } else if (lb_vip_is_gre4(vip)) { */
/* uword *p = ip4_get_route (&ip4_main, 0, 0, as->address.ip4.as_u8, 32); */
/* if (p == 0) { */
/* lb_put_writer_lock(); */
/* return VNET_API_ERROR_NO_SUCH_ENTRY; */
/* } */
/* u32 ai = (u32)p[0]; */
/* ip_lookup_main_t *lm4 = &ip4_main.lookup_main; */
/* ip_adjacency_t *adj4 = ip_get_adjacency (lm4, ai); */
/* if (adj4->lookup_next_index != IP_LOOKUP_NEXT_REWRITE) { */
/* lb_put_writer_lock(); */
/* return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE; */
/* } */
as->adj_index = ai;
} else {
u32 ai = ip6_get_route (&ip6_main, 0, 0, &as->address.ip6, 128);
if (ai == 0) {
lb_put_writer_lock();
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
/* as->adj_index = ai; */
/* } else { */
/* u32 ai = ip6_get_route (&ip6_main, 0, 0, &as->address.ip6, 128); */
/* if (ai == 0) { */
/* lb_put_writer_lock(); */
/* return VNET_API_ERROR_NO_SUCH_ENTRY; */
/* } */
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_REWRITE) {
lb_put_writer_lock();
return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
}
/* 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_REWRITE) { */
/* lb_put_writer_lock(); */
/* return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE; */
/* } */
as->adj_index = ai;
}
lb_put_writer_lock();
/* as->adj_index = ai; */
/* } */
/* lb_put_writer_lock(); */
return 0;
}
@@ -594,41 +594,41 @@ int lb_as_lookup_bypass(u32 vip_index, ip46_address_t *address, u8 is_disable)
*/
static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip)
{
ip_adjacency_t adj;
//Adjacency
memset (&adj, 0, sizeof (adj));
adj.explicit_fib_index = ~0;
lb_adj_data_t *ad = (lb_adj_data_t *) &adj.opaque;
ad->vip_index = vip - lbm->vips;
/* ip_adjacency_t adj; */
/* //Adjacency */
/* memset (&adj, 0, sizeof (adj)); */
/* adj.explicit_fib_index = ~0; */
/* lb_adj_data_t *ad = (lb_adj_data_t *) &adj.opaque; */
/* ad->vip_index = vip - lbm->vips; */
ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
u32 lookup_next_index = lbm->ip_lookup_next_index[vip->type];
/* ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned */
/* u32 lookup_next_index = lbm->ip_lookup_next_index[vip->type]; */
if (lb_vip_is_ip4(vip)) {
adj.lookup_next_index = lookup_next_index;
ip4_add_del_route_args_t route_args = {};
ip4_main_t *im4 = &ip4_main;
route_args.table_index_or_table_id = 0;
route_args.flags = IP4_ROUTE_FLAG_ADD;
route_args.dst_address = vip->prefix.ip4;
route_args.dst_address_length = vip->plen - 96;
route_args.adj_index = ~0;
route_args.add_adj = &adj;
route_args.n_add_adj = 1;
ip4_add_del_route (im4, &route_args);
} else {
adj.lookup_next_index = lookup_next_index;
ip6_add_del_route_args_t route_args = {};
ip6_main_t *im6 = &ip6_main;
route_args.table_index_or_table_id = 0;
route_args.flags = IP6_ROUTE_FLAG_ADD;
route_args.dst_address = vip->prefix.ip6;
route_args.dst_address_length = vip->plen;
route_args.adj_index = ~0;
route_args.add_adj = &adj;
route_args.n_add_adj = 1;
ip6_add_del_route (im6, &route_args);
}
/* if (lb_vip_is_ip4(vip)) { */
/* adj.lookup_next_index = lookup_next_index; */
/* ip4_add_del_route_args_t route_args = {}; */
/* ip4_main_t *im4 = &ip4_main; */
/* route_args.table_index_or_table_id = 0; */
/* route_args.flags = IP4_ROUTE_FLAG_ADD; */
/* route_args.dst_address = vip->prefix.ip4; */
/* route_args.dst_address_length = vip->plen - 96; */
/* route_args.adj_index = ~0; */
/* route_args.add_adj = &adj; */
/* route_args.n_add_adj = 1; */
/* ip4_add_del_route (im4, &route_args); */
/* } else { */
/* adj.lookup_next_index = lookup_next_index; */
/* ip6_add_del_route_args_t route_args = {}; */
/* ip6_main_t *im6 = &ip6_main; */
/* route_args.table_index_or_table_id = 0; */
/* route_args.flags = IP6_ROUTE_FLAG_ADD; */
/* route_args.dst_address = vip->prefix.ip6; */
/* route_args.dst_address_length = vip->plen; */
/* route_args.adj_index = ~0; */
/* route_args.add_adj = &adj; */
/* route_args.n_add_adj = 1; */
/* ip6_add_del_route (im6, &route_args); */
/* } */
}
/**
@@ -636,30 +636,30 @@ static void lb_vip_add_adjacency(lb_main_t *lbm, lb_vip_t *vip)
*/
static void lb_vip_del_adjacency(lb_main_t *lbm, lb_vip_t *vip)
{
ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned
if (lb_vip_is_ip4(vip)) {
ip4_main_t *im4 = &ip4_main;
ip4_add_del_route_args_t route_args = {};
route_args.table_index_or_table_id = 0;
route_args.flags = IP4_ROUTE_FLAG_DEL;
route_args.dst_address = vip->prefix.ip4;
route_args.dst_address_length = vip->plen - 96;
route_args.adj_index = ~0;
route_args.add_adj = NULL;
route_args.n_add_adj = 0;
ip4_add_del_route (im4, &route_args);
} else {
ip6_main_t *im6 = &ip6_main;
ip6_add_del_route_args_t route_args = {};
route_args.table_index_or_table_id = 0;
route_args.flags = IP6_ROUTE_FLAG_DEL;
route_args.dst_address = vip->prefix.ip6;
route_args.dst_address_length = vip->plen;
route_args.adj_index = ~0;
route_args.add_adj = NULL;
route_args.n_add_adj = 0;
ip6_add_del_route (im6, &route_args);
}
/* ASSERT (lbm->writer_lock[0]); //This must be called with the lock owned */
/* if (lb_vip_is_ip4(vip)) { */
/* ip4_main_t *im4 = &ip4_main; */
/* ip4_add_del_route_args_t route_args = {}; */
/* route_args.table_index_or_table_id = 0; */
/* route_args.flags = IP4_ROUTE_FLAG_DEL; */
/* route_args.dst_address = vip->prefix.ip4; */
/* route_args.dst_address_length = vip->plen - 96; */
/* route_args.adj_index = ~0; */
/* route_args.add_adj = NULL; */
/* route_args.n_add_adj = 0; */
/* ip4_add_del_route (im4, &route_args); */
/* } else { */
/* ip6_main_t *im6 = &ip6_main; */
/* ip6_add_del_route_args_t route_args = {}; */
/* route_args.table_index_or_table_id = 0; */
/* route_args.flags = IP6_ROUTE_FLAG_DEL; */
/* route_args.dst_address = vip->prefix.ip6; */
/* route_args.dst_address_length = vip->plen; */
/* route_args.adj_index = ~0; */
/* route_args.add_adj = NULL; */
/* route_args.n_add_adj = 0; */
/* ip6_add_del_route (im6, &route_args); */
/* } */
}
int lb_vip_add(ip46_address_t *prefix, u8 plen, lb_vip_type_t type, u32 new_length, u32 *vip_index)
+29 -29
View File
@@ -48,15 +48,15 @@ typedef struct {
u32 as_index;
} lb_trace_t;
u8 *lb_format_adjacency(u8 * s, va_list * va)
{
lb_main_t *lbm = &lb_main;
__attribute((unused)) ip_lookup_main_t *lm = va_arg (*va, ip_lookup_main_t *);
ip_adjacency_t *adj = va_arg (*va, ip_adjacency_t *);
lb_adj_data_t *ad = (lb_adj_data_t *) &adj->opaque;
__attribute__((unused)) lb_vip_t *vip = pool_elt_at_index (lbm->vips, ad->vip_index);
return format(s, "vip idx:%d", ad->vip_index);
}
/* u8 *lb_format_adjacency(u8 * s, va_list * va) */
/* { */
/* lb_main_t *lbm = &lb_main; */
/* __attribute((unused)) ip_lookup_main_t *lm = va_arg (*va, ip_lookup_main_t *); */
/* ip_adjacency_t *adj = va_arg (*va, ip_adjacency_t *); */
/* lb_adj_data_t *ad = (lb_adj_data_t *) &adj->opaque; */
/* __attribute__((unused)) lb_vip_t *vip = pool_elt_at_index (lbm->vips, ad->vip_index); */
/* return format(s, "vip idx:%d", ad->vip_index); */
/* } */
u8 *
format_lb_trace (u8 * s, va_list * args)
@@ -319,11 +319,11 @@ VLIB_REGISTER_NODE (lb6_gre6_node) =
},
};
VNET_IP6_REGISTER_ADJACENCY(lb6_gre6) = {
.node_name = "lb6-gre6",
.fn = lb_format_adjacency,
.next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP6_GRE6]
};
/* VNET_IP6_REGISTER_ADJACENCY(lb6_gre6) = { */
/* .node_name = "lb6-gre6", */
/* .fn = lb_format_adjacency, */
/* .next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP6_GRE6] */
/* }; */
VLIB_REGISTER_NODE (lb6_gre4_node) =
{
@@ -344,11 +344,11 @@ VLIB_REGISTER_NODE (lb6_gre4_node) =
},
};
VNET_IP6_REGISTER_ADJACENCY(lb6_gre4) = {
.node_name = "lb6-gre4",
.fn = lb_format_adjacency,
.next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP6_GRE4]
};
/* VNET_IP6_REGISTER_ADJACENCY(lb6_gre4) = { */
/* .node_name = "lb6-gre4", */
/* .fn = lb_format_adjacency, */
/* .next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP6_GRE4] */
/* }; */
VLIB_REGISTER_NODE (lb4_gre6_node) =
{
@@ -369,11 +369,11 @@ VLIB_REGISTER_NODE (lb4_gre6_node) =
},
};
VNET_IP4_REGISTER_ADJACENCY(lb4_gre6) = {
.node_name = "lb4-gre6",
.fn = lb_format_adjacency,
.next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP4_GRE6]
};
/* VNET_IP4_REGISTER_ADJACENCY(lb4_gre6) = { */
/* .node_name = "lb4-gre6", */
/* .fn = lb_format_adjacency, */
/* .next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP4_GRE6] */
/* }; */
VLIB_REGISTER_NODE (lb4_gre4_node) =
{
@@ -394,8 +394,8 @@ VLIB_REGISTER_NODE (lb4_gre4_node) =
},
};
VNET_IP4_REGISTER_ADJACENCY(lb4_gre4) = {
.node_name = "lb4-gre4",
.fn = lb_format_adjacency,
.next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP4_GRE4]
};
/* VNET_IP4_REGISTER_ADJACENCY(lb4_gre4) = { */
/* .node_name = "lb4-gre4", */
/* .fn = lb_format_adjacency, */
/* .next_index = &lb_main.ip_lookup_next_index[LB_VIP_TYPE_IP4_GRE4] */
/* }; */
+3 -1
View File
@@ -18,11 +18,13 @@ AM_LDFLAGS = -module -shared -avoid-version
libsixrd_plugin_la_SOURCES = \
sixrd/sixrd.c \
sixrd/sixrd_dpo.c \
sixrd/ip4_sixrd.c \
sixrd/ip6_sixrd.c
noinst_HEADERS = \
sixrd/sixrd.h
sixrd/sixrd.h \
sixrd/sixrd_dpo.h
BUILT_SOURCES =
+100 -110
View File
@@ -16,6 +16,10 @@
#include "sixrd.h"
#include <vnet/plugin/plugin.h>
#include <vnet/fib/fib_table.h>
#include <vnet/fib/ip6_fib.h>
#include <vnet/adj/adj.h>
/*
* This code supports the following sixrd modes:
*
@@ -29,21 +33,17 @@
int
sixrd_create_domain (ip6_address_t *ip6_prefix,
u8 ip6_prefix_len,
ip4_address_t *ip4_prefix,
u8 ip4_prefix_len,
ip4_address_t *ip4_src,
u32 *sixrd_domain_index,
u8 ip6_prefix_len,
ip4_address_t *ip4_prefix,
u8 ip4_prefix_len,
ip4_address_t *ip4_src,
u32 *sixrd_domain_index,
u16 mtu)
{
dpo_id_t dpo_v6 = DPO_NULL, dpo_v4 = DPO_NULL;
sixrd_main_t *mm = &sixrd_main;
ip4_main_t *im4 = &ip4_main;
ip6_main_t *im6 = &ip6_main;
fib_node_index_t fei;
sixrd_domain_t *d;
ip_adjacency_t adj;
ip4_add_del_route_args_t args4;
ip6_add_del_route_args_t args6;
u32 *p;
/* Get domain index */
pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES);
@@ -61,55 +61,79 @@ sixrd_create_domain (ip6_address_t *ip6_prefix,
if (ip4_prefix_len < 32)
d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len);
/* Init IP adjacency */
memset(&adj, 0, sizeof(adj));
adj.explicit_fib_index = ~0;
p = (u32 *)&adj.rewrite_data[0];
*p = (u32) (*sixrd_domain_index);
/* Create IPv6 route/adjacency */
fib_prefix_t pfx6 = {
.fp_proto = FIB_PROTOCOL_IP6,
.fp_len = d->ip6_prefix_len,
.fp_addr = {
.ip6 = d->ip6_prefix,
},
};
sixrd_dpo_create(FIB_PROTOCOL_IP6,
*sixrd_domain_index,
&dpo_v6);
fib_table_entry_special_dpo_add(0, &pfx6,
FIB_SOURCE_SIXRD,
FIB_ENTRY_FLAG_EXCLUSIVE,
&dpo_v6);
dpo_reset (&dpo_v6);
/* 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_prefix->as_u64[0];
args6.dst_address.as_u64[1] = ip6_prefix->as_u64[1];
args6.dst_address_length = ip6_prefix_len;
args6.adj_index = ~0;
args6.add_adj = &adj;
args6.n_add_adj = 1;
adj.lookup_next_index = mm->ip6_lookup_next_index;
ip6_add_del_route(im6, &args6);
/*
* Multiple SIXRD domains may share same source IPv4 TEP
* In this case the route will exist and be SixRD sourced.
* Find the adj (if any) already contributed and modify it
*/
fib_prefix_t pfx4 = {
.fp_proto = FIB_PROTOCOL_IP6,
.fp_len = 32,
.fp_addr = {
.ip4 = d->ip4_src,
},
};
fei = fib_table_lookup_exact_match(0, &pfx4);
/* Multiple SIXRD domains may share same source IPv4 TEP */
uword *q = ip4_get_route(im4, 0, 0, (u8 *)ip4_src, 32);
if (q) {
u32 ai = q[0];
ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
ip_adjacency_t *adj4 = ip_get_adjacency(lm4, ai);
if (adj4->lookup_next_index != mm->ip4_lookup_next_index) {
clib_warning("BR source address already assigned: %U", format_ip4_address, ip4_src);
pool_put(mm->domains, d);
return -1;
}
/* Shared source */
p = (u32 *)&adj4->rewrite_data[0];
p[0] = ~0;
if (FIB_NODE_INDEX_INVALID != fei)
{
dpo_id_t dpo = DPO_NULL;
/* Add refcount, so we don't accidentially delete the route underneath someone */
p[1]++;
} else {
/* 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_src->as_u32;
args4.dst_address_length = 32;
args4.adj_index = ~0;
args4.add_adj = &adj;
args4.n_add_adj = 1;
adj.lookup_next_index = mm->ip4_lookup_next_index;
ip4_add_del_route(im4, &args4);
if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo))
{
/*
* modify the existing adj to indicate it's shared
* skip to route add.
* It is locked to pair with the unlock below.
*/
const dpo_id_t *sd_dpo;
sixrd_dpo_t *sd;
ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type);
sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0);
sd = sixrd_dpo_get (sd_dpo->dpoi_index);
sd->sd_domain = ~0;
dpo_copy (&dpo_v4, sd_dpo);
dpo_reset (&dpo);
goto route_add;
}
}
/* first time addition of the route */
sixrd_dpo_create(FIB_PROTOCOL_IP4,
*sixrd_domain_index,
&dpo_v4);
route_add:
/*
* Create ip4 route. This is a reference counted add. If the prefix
* already exists and is SixRD sourced, it is now SixRD source n+1 times
* and will need to be removed n+1 times.
*/
fib_table_entry_special_dpo_add(0, &pfx4,
FIB_SOURCE_SIXRD,
FIB_ENTRY_FLAG_EXCLUSIVE,
&dpo_v4);
dpo_reset (&dpo_v4);
return 0;
}
@@ -121,57 +145,33 @@ int
sixrd_delete_domain (u32 sixrd_domain_index)
{
sixrd_main_t *mm = &sixrd_main;
ip4_main_t *im4 = &ip4_main;
ip6_main_t *im6 = &ip6_main;
sixrd_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, sixrd_domain_index)) {
clib_warning("SIXRD domain delete: domain does not exist: %d", sixrd_domain_index);
clib_warning("SIXRD domain delete: domain does not exist: %d",
sixrd_domain_index);
return -1;
}
d = pool_elt_at_index(mm->domains, sixrd_domain_index);
memset(&adj, 0, sizeof(adj));
adj.explicit_fib_index = ~0;
fib_prefix_t pfx = {
.fp_proto = FIB_PROTOCOL_IP4,
.fp_len = 32,
.fp_addr = {
.ip4 = d->ip4_src,
},
};
fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD);
/* Delete ip6 adjacency */
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_prefix.as_u64[0];
args6.dst_address.as_u64[1] = d->ip6_prefix.as_u64[1];
args6.dst_address_length = d->ip6_prefix_len;
args6.adj_index = 0;
args6.add_adj = &adj;
args6.n_add_adj = 0;
ip6_add_del_route(im6, &args6);
/* Delete ip4 adjacency */
uword *q = ip4_get_route(im4, 0, 0, (u8 *)&d->ip4_src, 32);
if (q) {
u32 ai = q[0];
ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
ip_adjacency_t *adj4 = ip_get_adjacency(lm4, ai);
u32 *p = (u32 *)&adj4->rewrite_data[0];
/* Delete route when no other domains use this source */
if (p[1] == 0) {
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);
}
p[1]--;
}
fib_prefix_t pfx6 = {
.fp_proto = FIB_PROTOCOL_IP6,
.fp_len = d->ip6_prefix_len,
.fp_addr = {
.ip6 = d->ip6_prefix,
},
};
fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD);
pool_put(mm->domains, d);
@@ -361,19 +361,9 @@ vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
static clib_error_t * sixrd_init (vlib_main_t * vm)
{
clib_error_t * error = 0;
sixrd_main_t *mm = &sixrd_main;
sixrd_dpo_module_init ();
vlib_node_t * ip6_lookup_node = vlib_get_node_by_name(vm, (u8 *)"ip6-lookup");
vlib_node_t * ip4_lookup_node = vlib_get_node_by_name(vm, (u8 *)"ip4-lookup");
vlib_node_t * ip6_sixrd_node = vlib_get_node_by_name(vm, (u8 *)"ip6-sixrd");
vlib_node_t * ip4_sixrd_node = vlib_get_node_by_name(vm, (u8 *)"ip4-sixrd");
ASSERT(ip6_lookup_node && ip4_lookup_node && ip6_sixrd_node && ip4_sixrd_node);
mm->ip6_lookup_next_index = vlib_node_add_next(vm, ip6_lookup_node->index, ip6_sixrd_node->index);
mm->ip4_lookup_next_index = vlib_node_add_next(vm, ip4_lookup_node->index, ip4_sixrd_node->index);
return error;
return (NULL);
}
VLIB_INIT_FUNCTION (sixrd_init);
+25 -28
View File
@@ -17,6 +17,9 @@
#include <vppinfra/error.h>
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/fib/ip6_fib.h>
#include "sixrd_dpo.h"
int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len,
ip4_address_t *ip4_prefix, u8 ip4_prefix_len,
@@ -44,9 +47,6 @@ typedef struct {
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
u32 ip4_lookup_next_index;
u32 ip6_lookup_next_index;
} sixrd_main_t;
#define foreach_sixrd_error \
@@ -99,16 +99,16 @@ sixrd_get_addr (sixrd_domain_t *d, u64 dal)
* Get the SIXRD domain from an IPv6 lookup adjacency.
*/
static_always_inline sixrd_domain_t *
ip6_sixrd_get_domain (u32 adj_index, u32 *sixrd_domain_index)
ip6_sixrd_get_domain (u32 sdi, u32 *sixrd_domain_index)
{
sixrd_main_t *mm = &sixrd_main;
ip_lookup_main_t *lm = &ip6_main.lookup_main;
ip_adjacency_t *adj = ip_get_adjacency(lm, adj_index);
ASSERT(adj);
uword *p = (uword *)adj->rewrite_data;
ASSERT(p);
*sixrd_domain_index = p[0];
return pool_elt_at_index(mm->domains, p[0]);
sixrd_dpo_t *sd;
sd = sixrd_dpo_get(sdi);
ASSERT(sd);
*sixrd_domain_index = sd->sd_domain;
return pool_elt_at_index(mm->domains, *sixrd_domain_index);
}
/*
@@ -117,28 +117,25 @@ ip6_sixrd_get_domain (u32 adj_index, u32 *sixrd_domain_index)
* The IPv6 address is used otherwise.
*/
static_always_inline sixrd_domain_t *
ip4_sixrd_get_domain (u32 adj_index, ip6_address_t *addr,
ip4_sixrd_get_domain (u32 sdi, ip6_address_t *addr,
u32 *sixrd_domain_index, u8 *error)
{
sixrd_main_t *mm = &sixrd_main;
ip6_main_t *im6 = &ip6_main;
ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
ip_adjacency_t *adj = ip_get_adjacency(lm4, adj_index);
ASSERT(adj);
uword *p = (uword *)adj->rewrite_data;
ASSERT(p);
*sixrd_domain_index = p[0];
if (p[0] != ~0)
return pool_elt_at_index(mm->domains, p[0]);
sixrd_dpo_t *sd;
u32 ai = ip6_fib_lookup_with_table(im6, 0, addr);
ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
if (PREDICT_TRUE(adj6->lookup_next_index == mm->ip6_lookup_next_index)) {
uword *p = (uword *)adj6->rewrite_data;
*sixrd_domain_index = p[0];
sd = sixrd_dpo_get(sdi);
*sixrd_domain_index = sd->sd_domain;
if (*sixrd_domain_index != ~0)
return pool_elt_at_index(mm->domains, *sixrd_domain_index);
}
u32 lbi = ip6_fib_table_fwding_lookup(&ip6_main, 0, addr);
const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0);
if (PREDICT_TRUE(dpo->dpoi_type == sixrd_dpo_type))
{
sd = sixrd_dpo_get(dpo->dpoi_index);
*sixrd_domain_index = sd->sd_domain;
return pool_elt_at_index(mm->domains, *sixrd_domain_index);
}
*error = SIXRD_ERROR_NO_DOMAIN;
return NULL;
}
+132
View File
@@ -0,0 +1,132 @@
/*
* 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 "sixrd_dpo.h"
#include <vnet/ip/ip.h>
/**
* pool of all MPLS Label DPOs
*/
sixrd_dpo_t *sixrd_dpo_pool;
/**
* The register SIXRD DPO type
*/
dpo_type_t sixrd_dpo_type;
static sixrd_dpo_t *
sixrd_dpo_alloc (void)
{
sixrd_dpo_t *sd;
pool_get_aligned(sixrd_dpo_pool, sd, CLIB_CACHE_LINE_BYTES);
memset(sd, 0, sizeof(*sd));
return (sd);
}
static index_t
sixrd_dpo_get_index (sixrd_dpo_t *sd)
{
return (sd - sixrd_dpo_pool);
}
void
sixrd_dpo_create (dpo_proto_t dproto,
u32 domain_index,
dpo_id_t *dpo)
{
sixrd_dpo_t *sd;
sd = sixrd_dpo_alloc();
sd->sd_domain = domain_index;
sd->sd_proto = dproto;
dpo_set(dpo,
sixrd_dpo_type,
dproto,
sixrd_dpo_get_index(sd));
}
u8*
format_sixrd_dpo (u8 *s, va_list *args)
{
index_t index = va_arg (*args, index_t);
CLIB_UNUSED(u32 indent) = va_arg (*args, u32);
sixrd_dpo_t *sd;
sd = sixrd_dpo_get(index);
return (format(s, "sixrd:[%d]:%U domain:%d",
index,
format_dpo_proto, sd->sd_proto,
sd->sd_domain));
}
static void
sixrd_dpo_lock (dpo_id_t *dpo)
{
sixrd_dpo_t *sd;
sd = sixrd_dpo_get(dpo->dpoi_index);
sd->sd_locks++;
}
static void
sixrd_dpo_unlock (dpo_id_t *dpo)
{
sixrd_dpo_t *sd;
sd = sixrd_dpo_get(dpo->dpoi_index);
sd->sd_locks--;
if (0 == sd->sd_locks)
{
pool_put(sixrd_dpo_pool, sd);
}
}
const static dpo_vft_t sd_vft = {
.dv_lock = sixrd_dpo_lock,
.dv_unlock = sixrd_dpo_unlock,
.dv_format = format_sixrd_dpo,
};
const static char* const sixrd_ip4_nodes[] =
{
"ip4-sixrd",
NULL,
};
const static char* const sixrd_ip6_nodes[] =
{
"ip6-sixrd",
NULL,
};
const static char* const * const sixrd_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_IP4] = sixrd_ip4_nodes,
[DPO_PROTO_IP6] = sixrd_ip6_nodes,
[DPO_PROTO_MPLS] = NULL,
};
void
sixrd_dpo_module_init (void)
{
sixrd_dpo_type = dpo_register_new_type(&sd_vft, sixrd_nodes);
}
+61
View File
@@ -0,0 +1,61 @@
/*
* 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 __SIXRD_DPO_H__
#define __SIXRD_DPO_H__
#include <vnet/vnet.h>
#include <vnet/dpo/dpo.h>
/**
* A representation of a 6RD DPO
*/
typedef struct sixrd_dpo_t
{
/**
* The dat-plane protocol
*/
dpo_proto_t sd_proto;
/**
* the SIXRD domain index
*/
u32 sd_domain;
/**
* Number of locks/users of the label
*/
u16 sd_locks;
} sixrd_dpo_t;
extern void sixrd_dpo_create (dpo_proto_t dproto,
u32 domain_index,
dpo_id_t *dpo);
/*
* Encapsulation violation for fast data-path access
*/
extern sixrd_dpo_t *sixrd_dpo_pool;
extern dpo_type_t sixrd_dpo_type;
static inline sixrd_dpo_t *
sixrd_dpo_get (index_t index)
{
return (pool_elt_at_index(sixrd_dpo_pool, index));
}
extern void sixrd_dpo_module_init(void);
#endif
+1 -1
View File
@@ -384,7 +384,7 @@ VLIB_REGISTER_NODE (vcgn_classify_node) = {
.next_nodes = {
[VCGN_CLASSIFY_NEXT_IP4_INPUT] = "ip4-input",
[VCGN_CLASSIFY_NEXT_IP6_INPUT] = "ip6-input",
[VCGN_CLASSIFY_NEXT_MPLS_INPUT] = "mpls-gre-input",
[VCGN_CLASSIFY_NEXT_MPLS_INPUT] = "mpls-input",
[VCGN_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input",
[VCGN_CLASSIFY_NEXT_UDP_INSIDE] = "vcgn-v4-udp-i2o",
[VCGN_CLASSIFY_NEXT_UDP_OUTSIDE] = "vcgn-v4-udp-o2i",
+104 -12
View File
@@ -13,7 +13,7 @@
AUTOMAKE_OPTIONS = foreign subdir-objects
AM_CFLAGS = -Wall @DPDK@ @IPSEC@ @IPV6SR@
AM_CFLAGS = -Wall -Werror @DPDK@ @IPSEC@ @IPV6SR@
libvnet_la_SOURCES =
libvnetplugin_la_SOURCES =
@@ -264,7 +264,6 @@ nobase_include_HEADERS += \
# Layer 3 protocol: IP v4/v6
########################################
libvnet_la_SOURCES += \
vnet/ip/adj_alloc.c \
vnet/ip/format.c \
vnet/ip/icmp4.c \
vnet/ip/icmp6.c \
@@ -296,7 +295,6 @@ libvnet_la_SOURCES += \
vnet/ip/ip_frag.c
nobase_include_HEADERS += \
vnet/ip/adj_alloc.h \
vnet/ip/format.h \
vnet/ip/icmp46_packet.h \
vnet/ip/icmp4.h \
@@ -369,13 +367,15 @@ nobase_include_HEADERS += \
########################################
libvnet_la_SOURCES += \
vnet/map/map.c \
vnet/map/map_dpo.c \
vnet/map/ip4_map.c \
vnet/map/ip6_map.c \
vnet/map/ip4_map_t.c \
vnet/map/ip6_map_t.c
nobase_include_HEADERS += \
vnet/map/map.h
vnet/map/map.h \
vnet/map/map_dpo.h
if ENABLE_TESTS
TESTS += test_map
@@ -422,16 +422,20 @@ nobase_include_HEADERS += \
# Tunnel protocol: gre+mpls
########################################
libvnet_la_SOURCES += \
vnet/mpls-gre/mpls.c \
vnet/mpls-gre/node.c \
vnet/mpls-gre/interface.c \
vnet/mpls-gre/policy_encap.c \
vnet/mpls-gre/pg.c
vnet/mpls/mpls.c \
vnet/mpls/mpls_lookup.c \
vnet/mpls/mpls_output.c \
vnet/mpls/mpls_features.c \
vnet/mpls/node.c \
vnet/mpls/interface.c \
vnet/mpls/policy_encap.c \
vnet/mpls/pg.c
nobase_include_HEADERS += \
vnet/mpls-gre/mpls.h \
vnet/mpls-gre/packet.h \
vnet/mpls-gre/error.def
vnet/mpls/mpls.h \
vnet/mpls/mpls_types.h \
vnet/mpls/packet.h \
vnet/mpls/error.def
########################################
@@ -466,6 +470,7 @@ nobase_include_HEADERS += \
libvnet_la_SOURCES += \
vnet/lisp-cp/lisp_types.c \
vnet/lisp-cp/lisp_cp_dpo.c \
vnet/lisp-cp/control.c \
vnet/lisp-cp/gid_dictionary.c \
vnet/lisp-cp/lisp_msg_serdes.c \
@@ -513,6 +518,9 @@ endif
libvnet_la_SOURCES += \
vnet/lisp-gpe/lisp_gpe.c \
vnet/lisp-gpe/lisp_gpe_sub_interface.c \
vnet/lisp-gpe/lisp_gpe_adjacency.c \
vnet/lisp-gpe/lisp_gpe_tunnel.c \
vnet/lisp-gpe/interface.c \
vnet/lisp-gpe/ip_forward.c \
vnet/lisp-gpe/decap.c
@@ -719,6 +727,90 @@ nobase_include_HEADERS += \
vnet/unix/tuntap.h \
vnet/unix/tapcli.h
########################################
# FIB
########################################
libvnet_la_SOURCES += \
vnet/fib/fib.c \
vnet/fib/fib_test.c \
vnet/fib/ip4_fib.c \
vnet/fib/ip6_fib.c \
vnet/fib/mpls_fib.c \
vnet/fib/fib_table.c \
vnet/fib/fib_walk.c \
vnet/fib/fib_types.c \
vnet/fib/fib_node.c \
vnet/fib/fib_node_list.c \
vnet/fib/fib_entry.c \
vnet/fib/fib_entry_src.c \
vnet/fib/fib_entry_src_rr.c \
vnet/fib/fib_entry_src_interface.c \
vnet/fib/fib_entry_src_default_route.c \
vnet/fib/fib_entry_src_special.c \
vnet/fib/fib_entry_src_api.c \
vnet/fib/fib_entry_src_adj.c \
vnet/fib/fib_entry_src_mpls.c \
vnet/fib/fib_entry_src_lisp.c \
vnet/fib/fib_entry_cover.c \
vnet/fib/fib_path_list.c \
vnet/fib/fib_path.c \
vnet/fib/fib_path_ext.c \
vnet/fib/fib_attached_export.c
nobase_include_HEADERS += \
vnet/fib/fib.h \
vnet/fib/ip4_fib.h \
vnet/fib/ip6_fib.h \
vnet/fib/fib_types.h \
vnet/fib/fib_table.h \
vnet/fib/fib_node.h \
vnet/fib/fib_node_list.h \
vnet/fib/fib_entry.h
########################################
# ADJ
########################################
libvnet_la_SOURCES += \
vnet/adj/adj_alloc.c \
vnet/adj/adj_nbr.c \
vnet/adj/adj_rewrite.c \
vnet/adj/adj_glean.c \
vnet/adj/adj_midchain.c \
vnet/adj/adj.c
nobase_include_HEADERS += \
vnet/adj/adj.h \
vnet/adj/adj_types.h \
vnet/adj/adj_rewrite.h \
vnet/adj/adj_glean.h \
vnet/adj/adj_nbr.h
########################################
# Data-Plane Objects
########################################
libvnet_la_SOURCES += \
vnet/dpo/dpo.c \
vnet/dpo/drop_dpo.c \
vnet/dpo/punt_dpo.c \
vnet/dpo/receive_dpo.c \
vnet/dpo/load_balance.c \
vnet/dpo/load_balance_map.c \
vnet/dpo/lookup_dpo.c \
vnet/dpo/classify_dpo.c \
vnet/dpo/mpls_label_dpo.c
nobase_include_HEADERS += \
vnet/dpo/load_balance.h \
vnet/dpo/drop_dpo.h \
vnet/dpo/lookup_dpo.h \
vnet/dpo/punt_dpo.h \
vnet/dpo/classify_dpo.h \
vnet/dpo/receive_dpo.h \
vnet/dpo/dpo.h
########################################
# Plugin client library
########################################
+24
View File
@@ -0,0 +1,24 @@
packet-generator new {
name x
limit 1
node ip4-input
size 64-64
no-recycle
data {
ICMP: 1.0.0.2 -> 2.2.2.2
ICMP echo_request
incrementing 100
}
}
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33
trace add pg-input 100
+26
View File
@@ -0,0 +1,26 @@
packet-generator new {
name x
limit 1
node ip4-input
size 64-64
no-recycle
data {
ICMP: 1.0.0.2 -> 2.2.2.2
ICMP echo_request
incrementing 100
}
}
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
set ip arp static loop1 2.0.0.2 dead.beef.babe
set int mpls loop1 enable
ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33
trace add pg-input 100
+28
View File
@@ -0,0 +1,28 @@
packet-generator new {
name x
limit 1
node mpls-input
size 72-72
no-recycle
data {
hex 0x0001e0ff0001f1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
}
}
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
set ip arp static loop1 2.0.0.2 dead.beef.babe
set int mpls loop1 enable
ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33
mpls local-label add 30 non-eos mpls-lookup-in-table 0
mpls local-label add 31 2.2.2.2/32
trace add pg-input 100
+27
View File
@@ -0,0 +1,27 @@
packet-generator new {
name x
limit 1
node mpls-input
size 68-68
no-recycle
data {
hex 0x0001e1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
}
}
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
set ip arp static loop1 2.0.0.2 dead.beef.babe
set int mpls loop1 enable
ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33
mpls local-label add 30 eos ip4-lookup-in-table 0
trace add pg-input 100
+26
View File
@@ -0,0 +1,26 @@
packet-generator new {
name x
limit 1
node mpls-input
size 68-68
no-recycle
data {
hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
}
}
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
set ip arp static loop1 2.0.0.2 dead.beef.babe
set int mpls loop1 enable
ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33
mpls local-label add 30 2.2.2.2/32
trace add pg-input 100
+10
View File
@@ -0,0 +1,10 @@
packet-generator new {
name x
limit 1
node mpls-ethernet-input
size 68-68
no-recycle
data {
hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
}
}
@@ -0,0 +1,17 @@
comment { single node configuration }
loop create
loop create
set int state loop0 up
set int state loop1 up
set int ip address loop0 1.0.0.1/24
set int ip address loop1 2.0.0.1/24
ip route add 2.2.2.2/32 via 2.0.0.2 loop1
mpls encap add label 30 fib 0 dest 2.2.2.2
mpls decap add label 30 fib 0
create mpls ethernet tunnel dst 00:50:56:b7:05:cb adj 2.2.2.2/32 tx-intfc loop1 fib-id 0
@@ -0,0 +1,63 @@
create loop int
set int state loop0 up
set int ip addr loop0 10.10.10.10/32
packet-generator new {
name deny-from-default-route
limit 1
node ip4-input
size 64-64
no-recycle
data {
UDP: 1.2.3.4 -> 5.6.7.8
UDP: 3000 -> 3001
length 128 checksum 0 incrementing 1
}
}
packet-generator new {
name allow
limit 1
node ip4-input
size 64-64
no-recycle
data {
UDP: 1.1.1.1 -> 5.6.7.8
UDP: 3000 -> 3001
length 128 checksum 0 incrementing 1
}
}
packet-generator new {
name deny-from-port-range
limit 1
node ip4-input
size 64-64
no-recycle
data {
UDP: 1.1.1.1 -> 5.6.7.8
UDP: 6000 -> 6001
length 128 checksum 0 incrementing 1
}
}
set ip source-and-port-range-check 1.1.1.0/24 range 2000 - 3000 vrf 99
set interface ip source-and-port-range-check pg0 udp-out-vrf 99
show ip source-and-port-range-check vrf 99 1.1.1.1
set ip source-and-port-range-check 1.1.1.0/24 range 4000 - 5000 vrf 99
set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99
show ip source-and-port-range-check vrf 99 1.1.1.1
show ip source-and-port-range-check vrf 99 1.1.2.1
set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99 del
show ip source-and-port-range-check vrf 99 1.1.2.1
tr add pg-input 100
+343
View File
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
/*
* 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.
*/
/**
* An adjacency is a representation of an attached L3 peer.
*
* Adjacency Sub-types:
* - neighbour: a representation of an attached L3 peer.
* Key:{addr,interface,link/ether-type}
* SHARED
* - glean: used to drive ARP/ND for packets destined to a local sub-net.
* 'glean' mean use the packet's destination address as the target
* address in the ARP packet.
* UNSHARED. Only one per-interface.
* - midchain: a nighbour adj on a virtual/tunnel interface.
* - rewrite: an adj with no key, but with a rewrite string.
*
* The API to create and update the adjacency is very sub-type specific. This
* is intentional as it encourages the user to carefully consider which adjacency
* sub-type they are really using, and hence assign it data in the appropriate
* sub-type space in the union of sub-types. This prevents the adj becoming a
* disorganised dumping group for 'my features needs a u16 somewhere' data. It
* is important to enforce this approach as space in the adjacency is a premium,
* as we need it to fit in 1 cache line.
*
* the API is also based around an index to an ajdacency not a raw pointer. This
* is so the user doesn't suffer the same limp inducing firearm injuries that
* the author suffered as the adjacenices can realloc.
*/
#ifndef __ADJ_H__
#define __ADJ_H__
#include <vnet/ip/lookup.h>
#include <vnet/adj/adj_types.h>
#include <vnet/adj/adj_nbr.h>
#include <vnet/adj/adj_rewrite.h>
#include <vnet/adj/adj_glean.h>
/**
* @brief
* Take a reference counting lock on the adjacency
*/
extern void adj_lock(adj_index_t adj_index);
/**
* @brief
* Release a reference counting lock on the adjacency
*/
extern void adj_unlock(adj_index_t adj_index);
/**
* @brief
* Add a child dependent to an adjacency. The child will
* thus be informed via its registerd back-walk function
* when the adjacency state changes.
*/
extern u32 adj_child_add(adj_index_t adj_index,
fib_node_type_t type,
fib_node_index_t child_index);
/**
* @brief
* Remove a child dependent
*/
extern void adj_child_remove(adj_index_t adj_index,
u32 sibling_index);
/**
* @brief
* The global adjacnecy heap. Exposed for fast/inline data-plane access
*/
extern ip_adjacency_t *adj_heap;
/**
* @brief
* Adjacency packet counters
*/
extern vlib_combined_counter_main_t adjacency_counters;
/**
* @brief
* Get a pointer to an adjacency object from its index
*/
static inline ip_adjacency_t *
adj_get (adj_index_t adj_index)
{
return (vec_elt_at_index(adj_heap, adj_index));
}
#endif
@@ -13,14 +13,18 @@
* limitations under the License.
*/
#include <vnet/ip/adj_alloc.h>
#include <vnet/adj/adj_alloc.h>
#include <vnet/ip/ip.h>
/*
* the single adj heap
*/
ip_adjacency_t *adj_heap;
/*
* any operation which could cause the adj vector to be reallocated
* must have a worker thread barrier
*/
static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
{
uword aligned_header_bytes, new_data_bytes;
@@ -45,13 +49,14 @@ static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
}
ip_adjacency_t *
aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
aa_alloc (void)
{
vlib_main_t * vm = &vlib_global_main;
aa_header_t * ah = aa_header (adjs);
aa_header_t * ah = aa_header (adj_heap);
ip_adjacency_t * adj_block;
u32 freelist_length;
int need_barrier_sync = 0;
u32 n = 1;
ASSERT(os_get_cpu_number() == 0);
ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
@@ -59,14 +64,14 @@ aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
/* If we don't have a freelist of size N, fresh allocation is required */
if (vec_len (ah->free_indices_by_size) <= n)
{
if (will_reallocate (adjs, n))
if (will_reallocate (adj_heap, n))
{
need_barrier_sync = 1;
vlib_worker_thread_barrier_sync (vm);
}
/* Workers wont look at the freelists... */
vec_validate (ah->free_indices_by_size, n);
vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
CLIB_CACHE_LINE_BYTES);
if (need_barrier_sync)
vlib_worker_thread_barrier_release (vm);
@@ -77,17 +82,17 @@ aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
{
u32 index = ah->free_indices_by_size[n][freelist_length-1];
adj_block = &adjs[index];
adj_block = &adj_heap[index];
_vec_len(ah->free_indices_by_size[n]) -= 1;
goto out;
}
/* Allocate a new block of size N */
if (will_reallocate (adjs, n))
if (will_reallocate (adj_heap, n))
{
need_barrier_sync = 1;
vlib_worker_thread_barrier_sync (vm);
}
vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
CLIB_CACHE_LINE_BYTES);
if (need_barrier_sync)
@@ -95,40 +100,45 @@ aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
out:
memset (adj_block, 0, n * (sizeof(*adj_block)));
adj_block->heap_handle = adj_block - adjs;
adj_block->heap_handle = adj_block - adj_heap;
adj_block->n_adj = n;
*blockp = adj_block;
return adjs;
/*
* the adj heap may have realloc'd. recache.
*/
ip4_main.lookup_main.adjacency_heap = adj_heap;
ip6_main.lookup_main.adjacency_heap = adj_heap;
return (adj_block);
}
void aa_free (ip_adjacency_t * adjs, ip_adjacency_t * adj)
void aa_free (ip_adjacency_t * adj)
{
aa_header_t * ah = aa_header (adjs);
aa_header_t * ah = aa_header (adj_heap);
ASSERT (adjs && adj && (adj->heap_handle < vec_len (adjs)));
ASSERT (adj->n_adj < vec_len (ah->free_indices_by_size));
ASSERT (adj_heap && adj && (adj->heap_handle < vec_len (adj_heap)));
ASSERT (adj->heap_handle != 0);
vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle);
adj->heap_handle = 0;
}
ip_adjacency_t * aa_bootstrap (ip_adjacency_t * adjs, u32 n)
void aa_bootstrap (u32 n)
{
ip_adjacency_t * adj_block;
aa_header_t * ah;
int i;
vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
CLIB_CACHE_LINE_BYTES);
memset (adj_block, 0, n * sizeof(*adj_block));
ah = aa_header (adjs);
ah = aa_header (adj_heap);
memset (ah, 0, sizeof (*ah));
vec_validate (ah->free_indices_by_size, 1);
for (i = 0 ; i < vec_len (adjs); i++)
for (i = 0 ; i < vec_len (adj_heap); i++)
{
adj_block->n_adj = 1;
adj_block->heap_handle = ~0;
@@ -136,24 +146,23 @@ ip_adjacency_t * aa_bootstrap (ip_adjacency_t * adjs, u32 n)
vec_add1 (ah->free_indices_by_size[1], n - (i+1));
}
return adjs;
ip4_main.lookup_main.adjacency_heap = adj_heap;
ip6_main.lookup_main.adjacency_heap = adj_heap;
}
u8 * format_adjacency_alloc (u8 * s, va_list * args)
{
vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
ip_adjacency_t * adjs = va_arg (*args, ip_adjacency_t *);
int verbose = va_arg (*args, int);
ip_adjacency_t * adj;
u32 inuse = 0, freed = 0;
u32 on_freelist = 0;
int i, j;
aa_header_t * ah = aa_header (adjs);
aa_header_t * ah = aa_header (adj_heap);
for (i = 0; i < vec_len (adjs); i += adj->n_adj)
for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
{
adj = adjs + i;
adj = adj_heap + i;
if ((i == 0) || adj->heap_handle)
inuse += adj->n_adj;
else
@@ -164,19 +173,19 @@ u8 * format_adjacency_alloc (u8 * s, va_list * args)
{
for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++)
{
adj = adjs + ah->free_indices_by_size[i][j];
adj = adj_heap + ah->free_indices_by_size[i][j];
ASSERT(adj->heap_handle == 0);
on_freelist += adj->n_adj;
}
}
s = format (s, "adjs: %d total, %d in use, %d free, %d on freelists\n",
vec_len(adjs), inuse, freed, on_freelist);
s = format (s, "adj_heap: %d total, %d in use, %d free, %d on freelists\n",
vec_len(adj_heap), inuse, freed, on_freelist);
if (verbose)
{
for (i = 0; i < vec_len (adjs); i += adj->n_adj)
for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
{
adj = adjs + i;
adj = adj_heap + i;
if ((i == 0) || adj->heap_handle)
{
if (adj->n_adj > 1)
@@ -190,7 +199,7 @@ u8 * format_adjacency_alloc (u8 * s, va_list * args)
s = format (s, " ");
s = format(s, "%U\n", format_ip_adjacency,
vnm, lm, i+j);
vnm, i+j, FORMAT_IP_ADJACENCY_NONE);
}
}
}
@@ -200,36 +209,22 @@ u8 * format_adjacency_alloc (u8 * s, va_list * args)
static clib_error_t *
show_adjacency_alloc_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
int verbose = 0;
vnet_main_t *vnm = vnet_get_main();
ip_lookup_main_t *lm = 0;
ip_adjacency_t * adjs = 0;
int is_ip4 = 1;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "verbose"))
verbose = 1;
else if (unformat (input, "ip4"))
;
else if (unformat (input, "ip6"))
is_ip4 = 0;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
if (is_ip4)
lm = &ip4_main.lookup_main;
else
lm = &ip6_main.lookup_main;
adjs = lm->adjacency_heap;
vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, lm, adjs, verbose);
vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, verbose);
return 0;
}
@@ -16,7 +16,8 @@
#ifndef __adj_alloc_h__
#define __adj_alloc_h__
/*
/**
* @brief
* Adjacency allocator: heap-like in that the code
* will dole out contiguous chunks of n items. In the interests of
* thread safety, we don't bother about coalescing free blocks of size r
@@ -43,10 +44,9 @@ static inline aa_header_t * aa_header (void * v)
return vec_aligned_header (v, sizeof (aa_header_t), sizeof (void *));
}
ip_adjacency_t *
aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n);
void aa_free (ip_adjacency_t * adjs, ip_adjacency_t * adj);
ip_adjacency_t * aa_bootstrap (ip_adjacency_t * adjs, u32 n);
extern ip_adjacency_t *aa_alloc(void);
extern void aa_free (ip_adjacency_t * adj);
extern void aa_bootstrap (u32 n);
format_function_t format_adj_allocation;
+246
View File
@@ -0,0 +1,246 @@
/*
* 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/adj/adj.h>
#include <vnet/adj/adj_alloc.h>
#include <vnet/adj/adj_internal.h>
#include <vnet/fib/fib_walk.h>
/*
* The 'DB' of all glean adjs.
* There is only one glean per-interface per-protocol, so this is a per-interface
* vector
*/
static adj_index_t *adj_gleans[FIB_PROTOCOL_MAX];
static inline vlib_node_registration_t*
adj_get_glean_node (fib_protocol_t proto)
{
switch (proto) {
case FIB_PROTOCOL_IP4:
return (&ip4_glean_node);
case FIB_PROTOCOL_IP6:
return (&ip6_glean_node);
case FIB_PROTOCOL_MPLS:
break;
}
ASSERT(0);
return (NULL);
}
/*
* adj_glean_add_or_lock
*
* The next_hop address here is used for source address selection in the DP.
* The glean adj is added to an interface's connected prefix, the next-hop
* passed here is the local prefix on the same interface.
*/
adj_index_t
adj_glean_add_or_lock (fib_protocol_t proto,
u32 sw_if_index,
const ip46_address_t *nh_addr)
{
ip_adjacency_t * adj;
vec_validate_init_empty(adj_gleans[proto], sw_if_index, ADJ_INDEX_INVALID);
if (ADJ_INDEX_INVALID == adj_gleans[proto][sw_if_index])
{
adj = adj_alloc(proto);
adj->lookup_next_index = IP_LOOKUP_NEXT_GLEAN;
adj->ia_nh_proto = proto;
adj_gleans[proto][sw_if_index] = adj->heap_handle;
if (NULL != nh_addr)
{
adj->sub_type.glean.receive_addr = *nh_addr;
}
adj->rewrite_header.data_bytes = 0;
vnet_rewrite_for_sw_interface(vnet_get_main(),
adj_fib_proto_2_nd(proto),
sw_if_index,
adj_get_glean_node(proto)->index,
VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST,
&adj->rewrite_header,
sizeof (adj->rewrite_data));
}
else
{
adj = adj_get(adj_gleans[proto][sw_if_index]);
}
adj_lock(adj->heap_handle);
return (adj->heap_handle);
}
void
adj_glean_remove (fib_protocol_t proto,
u32 sw_if_index)
{
ASSERT(sw_if_index < vec_len(adj_gleans[proto]));
adj_gleans[proto][sw_if_index] = ADJ_INDEX_INVALID;
}
static clib_error_t *
adj_glean_interface_state_change (vnet_main_t * vnm,
u32 sw_if_index,
u32 flags)
{
/*
* for each glean on the interface trigger a walk back to the children
*/
fib_protocol_t proto;
ip_adjacency_t *adj;
for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
{
if (sw_if_index >= vec_len(adj_gleans[proto]) ||
ADJ_INDEX_INVALID == adj_gleans[proto][sw_if_index])
continue;
adj = adj_get(adj_gleans[proto][sw_if_index]);
fib_node_back_walk_ctx_t bw_ctx = {
.fnbw_reason = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ?
FIB_NODE_BW_REASON_FLAG_INTERFACE_UP :
FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN),
};
fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx);
}
return (NULL);
}
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(adj_glean_interface_state_change);
static clib_error_t *
adj_glean_interface_delete (vnet_main_t * vnm,
u32 sw_if_index,
u32 is_add)
{
/*
* for each glean on the interface trigger a walk back to the children
*/
fib_protocol_t proto;
ip_adjacency_t *adj;
if (is_add)
{
/*
* not interested in interface additions. we will not back walk
* to resolve paths through newly added interfaces. Why? The control
* plane should have the brains to add interfaces first, then routes.
* So the case where there are paths with a interface that matches
* one just created is the case where the path resolved through an
* interface that was deleted, and still has not been removed. The
* new interface added, is NO GUARANTEE that the interface being
* added now, even though it may have the same sw_if_index, is the
* same interface that the path needs. So tough!
* If the control plane wants these routes to resolve it needs to
* remove and add them again.
*/
return (NULL);
}
for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
{
if (sw_if_index >= vec_len(adj_gleans[proto]) ||
ADJ_INDEX_INVALID == adj_gleans[proto][sw_if_index])
continue;
adj = adj_get(adj_gleans[proto][sw_if_index]);
fib_node_back_walk_ctx_t bw_ctx = {
.fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE,
};
fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx);
}
return (NULL);
}
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_glean_interface_delete);
u8*
format_adj_glean (u8* s, va_list *ap)
{
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);
return (format(s, " glean: %U",
format_vnet_sw_interface_name,
vnm,
vnet_get_sw_interface(vnm,
adj->rewrite_header.sw_if_index)));
}
static void
adj_dpo_lock (dpo_id_t *dpo)
{
adj_lock(dpo->dpoi_index);
}
static void
adj_dpo_unlock (dpo_id_t *dpo)
{
adj_unlock(dpo->dpoi_index);
}
const static dpo_vft_t adj_glean_dpo_vft = {
.dv_lock = adj_dpo_lock,
.dv_unlock = adj_dpo_unlock,
.dv_format = format_adj_glean,
};
/**
* @brief The per-protocol VLIB graph nodes that are assigned to a glean
* object.
*
* this means that these graph nodes are ones from which a glean is the
* parent object in the DPO-graph.
*/
const static char* const glean_ip4_nodes[] =
{
"ip4-glean",
NULL,
};
const static char* const glean_ip6_nodes[] =
{
"ip6-glean",
NULL,
};
const static char* const * const glean_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_IP4] = glean_ip4_nodes,
[DPO_PROTO_IP6] = glean_ip6_nodes,
[DPO_PROTO_MPLS] = NULL,
};
void
adj_glean_module_init (void)
{
dpo_register(DPO_ADJACENCY_GLEAN, &adj_glean_dpo_vft, glean_nodes);
}
+56
View File
@@ -0,0 +1,56 @@
/*
* 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.
*/
/**
* @brief Glean Adjacency
*
* A gleean adjacency represent the need to discover new peers on an
* attached link. Packets that hit a glean adjacency will generate an
* ARP/ND packet addessesed to the packet's destination address.
* Note this is different to an incomplete neighbour adjacency, which
* does not send ARP/ND requests to the packet's destination address,
* but instead to the next-hop address of the adjacency itself.
*/
#ifndef __ADJ_GLEAN_H__
#define __ADJ_GLEAN_H__
#include <vnet/adj/adj_types.h>
/**
* @brief
* Add (and lock) a new or lock an existing glean adjacency
*
* @param proto
* The protocol for the neighbours that we wish to glean
*
* @param sw_if_index
* The interface on which to glean
*
* @param nh_addr
* the address applied to the interface on which to glean. This
* as the source address in packets when the ARP/ND packet is sent
*/
extern adj_index_t adj_glean_add_or_lock(fib_protocol_t proto,
u32 sw_if_index,
const ip46_address_t *nh_addr);
/**
* @brief
* Module initialisation
*/
extern void adj_glean_module_init(void);
#endif
+97
View File
@@ -0,0 +1,97 @@
/*
* 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 __ADJ_INTERNAL_H__
#define __ADJ_INTERNAL_H__
#include <vnet/adj/adj.h>
#include <vnet/ip/ip.h>
#include <vnet/mpls/mpls.h>
/**
* big switch to turn on Adjacency debugging
*/
#undef ADJ_DEBUG
/*
* Debug macro
*/
#ifdef ADJ_DEBUG
#define ADJ_DBG(_adj, _fmt, _args...) \
{ \
clib_warning("adj:[%d:%p]:" _fmt, \
_adj->heap_handle, _adj, \
##_args); \
}
#else
#define ADJ_DBG(_e, _fmt, _args...)
#endif
static inline vlib_node_registration_t*
adj_get_rewrite_node (fib_link_t linkt)
{
switch (linkt) {
case FIB_LINK_IP4:
return (&ip4_rewrite_node);
case FIB_LINK_IP6:
return (&ip6_rewrite_node);
case FIB_LINK_MPLS:
return (&mpls_output_node);
}
ASSERT(0);
return (NULL);
}
static inline vnet_l3_packet_type_t
adj_fib_link_2_vnet (fib_link_t linkt)
{
switch (linkt)
{
case FIB_LINK_IP4:
return (VNET_L3_PACKET_TYPE_IP4);
case FIB_LINK_IP6:
return (VNET_L3_PACKET_TYPE_IP6);
case FIB_LINK_MPLS:
return (VNET_L3_PACKET_TYPE_MPLS_UNICAST);
}
return (0);
}
static inline vnet_l3_packet_type_t
adj_fib_proto_2_nd (fib_protocol_t fp)
{
switch (fp)
{
case FIB_PROTOCOL_IP4:
return (VNET_L3_PACKET_TYPE_ARP);
case FIB_PROTOCOL_IP6:
return (VNET_L3_PACKET_TYPE_IP6);
case FIB_PROTOCOL_MPLS:
return (VNET_L3_PACKET_TYPE_MPLS_UNICAST);
}
return (0);
}
extern ip_adjacency_t * adj_alloc(fib_protocol_t proto);
extern void adj_nbr_remove(fib_protocol_t nh_proto,
fib_link_t link_type,
const ip46_address_t *nh_addr,
u32 sw_if_index);
extern void adj_glean_remove(fib_protocol_t proto,
u32 sw_if_index);
#endif
+226
View File
@@ -0,0 +1,226 @@
/*
* 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/adj/adj_nbr.h>
#include <vnet/adj/adj_internal.h>
#include <vnet/ethernet/arp_packet.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/fib/fib_walk.h>
static inline u32
adj_get_midchain_node (fib_link_t link)
{
switch (link) {
case FIB_LINK_IP4:
return (ip4_midchain_node.index);
case FIB_LINK_IP6:
return (ip6_midchain_node.index);
case FIB_LINK_MPLS:
return (mpls_midchain_node.index);
}
ASSERT(0);
return (0);
}
/**
* adj_nbr_midchain_update_rewrite
*
* Update the adjacency's rewrite string. A NULL string implies the
* rewrite is reset (i.e. when ARP/ND etnry is gone).
* NB: the adj being updated may be handling traffic in the DP.
*/
void
adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
u32 post_rewrite_node,
u8 *rewrite)
{
ip_adjacency_t *adj;
ASSERT(ADJ_INDEX_INVALID != adj_index);
adj = adj_get(adj_index);
adj->lookup_next_index = IP_LOOKUP_NEXT_MIDCHAIN;
adj->sub_type.midchain.tx_function_node = post_rewrite_node;
if (NULL != rewrite)
{
/*
* new rewrite provided.
* use a dummy rewrite header to get the interface to print into.
*/
ip_adjacency_t dummy;
dpo_id_t tmp = DPO_NULL;
vnet_rewrite_for_tunnel(vnet_get_main(),
adj->rewrite_header.sw_if_index,
adj_get_midchain_node(adj->ia_link),
adj->sub_type.midchain.tx_function_node,
&dummy.rewrite_header,
rewrite,
vec_len(rewrite));
/*
* this is an update of an existing rewrite.
* packets are in flight. we'll need to briefly stack on the drop DPO
* whilst the rewrite is written, so any packets that see the partial update
* are binned.
*/
if (!dpo_id_is_valid(&adj->sub_type.midchain.next_dpo))
{
/*
* not stacked yet. stack on the drop
*/
dpo_stack(DPO_ADJACENCY_MIDCHAIN,
fib_proto_to_dpo(adj->ia_nh_proto),
&adj->sub_type.midchain.next_dpo,
drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
}
dpo_copy(&tmp, &adj->sub_type.midchain.next_dpo);
dpo_stack(DPO_ADJACENCY_MIDCHAIN,
fib_proto_to_dpo(adj->ia_nh_proto),
&adj->sub_type.midchain.next_dpo,
drop_dpo_get(fib_proto_to_dpo(adj->ia_nh_proto)));
CLIB_MEMORY_BARRIER();
clib_memcpy(&adj->rewrite_header,
&dummy.rewrite_header,
VLIB_BUFFER_PRE_DATA_SIZE);
CLIB_MEMORY_BARRIER();
/*
* The graph arc used/created here is from the post-rewirte node to the
* child's registered node. This is because post adj processing the next
* node is the interface's specific node, then the post-write-node (aka
* the interface's tx-function) - from there we need to get to the stacked
* child's node.
*/
dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
&adj->sub_type.midchain.next_dpo,
&tmp);
dpo_reset(&tmp);
}
else
{
ASSERT(0);
}
/*
* time for walkies fido.
*/
fib_node_back_walk_ctx_t bw_ctx = {
.fnbw_reason = FIB_NODE_BW_REASON_ADJ_UPDATE,
};
fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx);
}
/**
* adj_nbr_midchain_stack
*/
void
adj_nbr_midchain_stack (adj_index_t adj_index,
const dpo_id_t *next)
{
ip_adjacency_t *adj;
ASSERT(ADJ_INDEX_INVALID != adj_index);
adj = adj_get(adj_index);
ASSERT(IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index);
dpo_stack_from_node(adj->sub_type.midchain.tx_function_node,
&adj->sub_type.midchain.next_dpo,
next);
}
u8*
format_adj_midchain (u8* s, va_list *ap)
{
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_fib_link, adj->ia_link);
s = format (s, " via %U ",
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);
s = format (s, "\n%Ustacked-on:\n%U%U",
format_white_space, indent,
format_white_space, indent+2,
format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
return (s);
}
static void
adj_dpo_lock (dpo_id_t *dpo)
{
adj_lock(dpo->dpoi_index);
}
static void
adj_dpo_unlock (dpo_id_t *dpo)
{
adj_unlock(dpo->dpoi_index);
}
const static dpo_vft_t adj_midchain_dpo_vft = {
.dv_lock = adj_dpo_lock,
.dv_unlock = adj_dpo_unlock,
.dv_format = format_adj_midchain,
};
/**
* @brief The per-protocol VLIB graph nodes that are assigned to a midchain
* object.
*
* this means that these graph nodes are ones from which a midchain is the
* parent object in the DPO-graph.
*/
const static char* const midchain_ip4_nodes[] =
{
"ip4-midchain",
NULL,
};
const static char* const midchain_ip6_nodes[] =
{
"ip6-midchain",
NULL,
};
const static char* const midchain_mpls_nodes[] =
{
"mpls-midchain",
NULL,
};
const static char* const * const midchain_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_IP4] = midchain_ip4_nodes,
[DPO_PROTO_IP6] = midchain_ip6_nodes,
[DPO_PROTO_MPLS] = midchain_mpls_nodes,
};
void
adj_midchain_module_init (void)
{
dpo_register(DPO_ADJACENCY_MIDCHAIN, &adj_midchain_dpo_vft, midchain_nodes);
}
+71
View File
@@ -0,0 +1,71 @@
/*
* 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.
*/
/**
* Midchain Adjacency sub-type. These adjs represent an L3 peer on a
* tunnel interface. The tunnel's adjacency is thus not the end of the chain,
* and needs to stack on/link to another chain (or portion of the graph) to
* reach the tunnel's destination.
*/
#ifndef __ADJ_MIDCHAIN_H__
#define __ADJ_MIDCHAIN_H__
#include <vnet/adj/adj.h>
/**
* @brief
* Convert an existing neighbour adjacency into a midchain
*
* @param adj_index
* The index of the neighbour adjacency.
*
* @param post_rewrite_node
* The VLIB graph node that provides the post-encap fixup.
* where 'fixup' is e.g., correcting chksum, length, etc.
*
* @param rewrite
* The rewrite.
*/
extern void adj_nbr_midchain_update_rewrite(adj_index_t adj_index,
u32 post_rewrite_node,
u8 *rewrite);
/**
* @brief
* [re]stack a midchain. 'Stacking' is the act of forming parent-child
* relationships in the data-plane graph.
*
* @param adj_index
* The index of the midchain to stack
*
* @param dpo
* The parent DPO to stack onto (i.e. become a child of).
*/
extern void adj_nbr_midchain_stack(adj_index_t adj_index,
const dpo_id_t *dpo);
/**
* @brief
* Module initialisation
*/
extern void adj_midchain_module_init(void);
/**
* @brief
* Format a midchain adjacency
*/
extern u8* format_adj_midchain(u8* s, va_list *ap);
#endif
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More