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:
committed by
Damjan Marion
parent
60537f3d83
commit
0bfe5d8c79
+2
-2
@@ -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
|
||||
|
||||
+245
-137
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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] */
|
||||
/* }; */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
########################################
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user