aboutsummaryrefslogtreecommitdiffstats
path: root/vnet
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2016-06-14 18:38:02 -0400
committerKeith Burns <alagalah@gmail.com>2016-06-17 16:24:16 +0000
commitd65346098daf8967e882d0299679a131769c9be9 (patch)
tree50a9bb16a3f2c1ef8a9ef6b5e2623564a8453a5d /vnet
parent378893a485d0e0dd331cebcb2ebefdeca073b1ab (diff)
Dynamically compute ip feature subgraph order
This change-set enables plugins to add themselves to the ip4/ip6 feature subgraphs without having to modify core vpp engine code at all. Add VNET_IP4/IP6_UNICAST/MULTICAST_FEATURE_INIT macros which express the required ordering constraints, and off you go. Along the way, added an implementation of Warshall's algorithm to vppinfra; to compute the positive transitive closure of a relation. In this case, the relation is "feature A runs before feature B." With that in hand, ip_feature_init_cast(...) computes a partial order across the set of configured feature subgraph nodes. In unit-testing, we discovered VPP-145 - ip4/6 inacl wiped out vnet_buffer(b)->ip>current_config_index, which exists in main. So, we fixed that by moving b->trace_index, adding b->current_config_index, and removing the ip opaque union current_config_index. Change-Id: Iff132116f66413dc6b31ac3377198c7a32d51f48 Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'vnet')
-rw-r--r--vnet/Makefile.am2
-rw-r--r--vnet/vnet/buffer.h3
-rw-r--r--vnet/vnet/classify/input_acl.c4
-rw-r--r--vnet/vnet/ip/ip.h1
-rw-r--r--vnet/vnet/ip/ip4.h66
-rw-r--r--vnet/vnet/ip/ip4_forward.c121
-rw-r--r--vnet/vnet/ip/ip4_input.c12
-rw-r--r--vnet/vnet/ip/ip4_source_check.c12
-rw-r--r--vnet/vnet/ip/ip6.h66
-rw-r--r--vnet/vnet/ip/ip6_forward.c97
-rw-r--r--vnet/vnet/ip/ip6_input.c12
-rw-r--r--vnet/vnet/ip/ip_feature_registration.c207
-rw-r--r--vnet/vnet/ip/ip_feature_registration.h35
-rw-r--r--vnet/vnet/ip/ip_input_acl.c2
-rw-r--r--vnet/vnet/ipsec/ipsec.c4
-rw-r--r--vnet/vnet/ipsec/ipsec_input.c4
-rw-r--r--vnet/vnet/l2tp/decap.c2
-rw-r--r--vnet/vnet/l2tp/l2tp.c6
-rw-r--r--vnet/vnet/misc.c9
19 files changed, 530 insertions, 135 deletions
diff --git a/vnet/Makefile.am b/vnet/Makefile.am
index 61a1998a6eb..d0a06be8e9e 100644
--- a/vnet/Makefile.am
+++ b/vnet/Makefile.am
@@ -248,6 +248,7 @@ libvnet_la_SOURCES += \
vnet/ip/format.c \
vnet/ip/icmp4.c \
vnet/ip/icmp6.c \
+ vnet/ip/ip_feature_registration.c \
vnet/ip/ip46_cli.c \
vnet/ip/ip4_format.c \
vnet/ip/ip4_forward.c \
@@ -280,6 +281,7 @@ nobase_include_HEADERS += \
vnet/ip/icmp6.h \
vnet/ip/igmp_packet.h \
vnet/ip/ip.h \
+ vnet/ip/ip_feature_registration.h \
vnet/ip/ip4.h \
vnet/ip/ip4_mtrie.h \
vnet/ip/ip4_error.h \
diff --git a/vnet/vnet/buffer.h b/vnet/vnet/buffer.h
index ea25ad0d286..f74be393df1 100644
--- a/vnet/vnet/buffer.h
+++ b/vnet/vnet/buffer.h
@@ -113,9 +113,6 @@ typedef struct {
union {
struct {
- /* Current configuration index. */
- u32 current_config_index;
-
/* Flow hash value for this packet computed from IP src/dst address
protocol and ports. */
u32 flow_hash;
diff --git a/vnet/vnet/classify/input_acl.c b/vnet/vnet/classify/input_acl.c
index 7e835a697f8..fb9a2a46b08 100644
--- a/vnet/vnet/classify/input_acl.c
+++ b/vnet/vnet/classify/input_acl.c
@@ -41,12 +41,12 @@ vnet_inacl_ip_feature_enable (vlib_main_t * vnm,
if (tid == INPUT_ACL_TABLE_IP4)
{
lm = &ip4_main.lookup_main;
- ftype = IP4_RX_FEATURE_CHECK_ACCESS;
+ ftype = ip4_main.ip4_unicast_rx_feature_check_access;
}
else
{
lm = &ip6_main.lookup_main;
- ftype = IP6_RX_FEATURE_CHECK_ACCESS;
+ ftype = ip6_main.ip6_unicast_rx_feature_check_access;
}
ipcm = &lm->rx_config_mains[VNET_UNICAST];
diff --git a/vnet/vnet/ip/ip.h b/vnet/vnet/ip/ip.h
index 45062cf7b4d..c9a82930a67 100644
--- a/vnet/vnet/ip/ip.h
+++ b/vnet/vnet/ip/ip.h
@@ -42,6 +42,7 @@
#include <vppinfra/hash.h>
#include <vppinfra/heap.h> /* adjacency heap */
+#include <vppinfra/ptclosure.h>
#include <vnet/vnet.h>
diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h
index 59ef685bc57..c01006ea590 100644
--- a/vnet/vnet/ip/ip4.h
+++ b/vnet/vnet/ip/ip4.h
@@ -43,6 +43,7 @@
#include <vnet/ip/ip4_mtrie.h>
#include <vnet/ip/ip4_packet.h>
#include <vnet/ip/lookup.h>
+#include <vnet/ip/ip_feature_registration.h>
typedef struct ip4_fib_t {
/* Hash table for each prefix length mapping. */
@@ -101,30 +102,6 @@ typedef struct {
uword function_opaque;
} ip4_add_del_interface_address_callback_t;
-typedef enum {
- /* First check access list to either permit or deny this
- packet based on classification. */
- IP4_RX_FEATURE_CHECK_ACCESS,
-
- /* RPF check: verify that source address is reachable via
- RX interface or via any interface. */
- IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_RX,
- IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_ANY,
-
- /* IPSec */
- IP4_RX_FEATURE_IPSEC,
-
- /* vPath forwarding: won't return to call next feature
- so any feature needed before vPath forwarding must be prior
- to this entry */
- IP4_RX_FEATURE_VPATH,
-
- /* Must be last: perform forwarding lookup. */
- IP4_RX_FEATURE_LOOKUP,
-
- IP4_N_RX_FEATURE,
-} ip4_rx_feature_type_t;
-
typedef struct ip4_main_t {
ip_lookup_main_t lookup_main;
@@ -152,6 +129,22 @@ typedef struct ip4_main_t {
/* Template used to generate IP4 ARP packets. */
vlib_packet_template_t ip4_arp_request_packet_template;
+ /* feature path configuration lists */
+ vnet_ip_feature_registration_t * next_uc_feature;
+ vnet_ip_feature_registration_t * next_mc_feature;
+
+ /* Built-in unicast feature path indices, see ip_feature_init_cast(...) */
+ u32 ip4_unicast_rx_feature_check_access;
+ u32 ip4_unicast_rx_feature_source_reachable_via_rx;
+ u32 ip4_unicast_rx_feature_source_reachable_via_any;
+ u32 ip4_unicast_rx_feature_ipsec;
+ u32 ip4_unicast_rx_feature_vpath;
+ u32 ip4_unicast_rx_feature_lookup;
+
+ /* Built-in multicast feature path indices */
+ u32 ip4_multicast_rx_feature_vpath;
+ u32 ip4_multicast_rx_feature_lookup;
+
/* Seed for Jenkins hash used to compute ip4 flow hash. */
u32 flow_hash_seed;
@@ -169,6 +162,31 @@ typedef struct ip4_main_t {
/* Global ip4 main structure. */
extern ip4_main_t ip4_main;
+#define VNET_IP4_UNICAST_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t uc_##x; \
+static void __vnet_add_feature_registration_uc_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_uc_##x (void) \
+{ \
+ ip4_main_t * im = &ip4_main; \
+ uc_##x.next = im->next_uc_feature; \
+ im->next_uc_feature = &uc_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t uc_##x
+
+#define VNET_IP4_MULTICAST_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t mc_##x; \
+static void __vnet_add_feature_registration_mc_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_mc_##x (void) \
+{ \
+ ip4_main_t * im = &ip4_main; \
+ mc_##x.next = im->next_mc_feature; \
+ im->next_mc_feature = &mc_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t mc_##x
+
+
/* Global ip4 input node. Errors get attached to ip4 input node. */
extern vlib_node_registration_t ip4_input_node;
extern vlib_node_registration_t ip4_lookup_node;
diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c
index 94c446b1f38..1de0b40eb78 100644
--- a/vnet/vnet/ip/ip4_forward.c
+++ b/vnet/vnet/ip/ip4_forward.c
@@ -1284,6 +1284,83 @@ ip4_sw_interface_admin_up_down (vnet_main_t * vnm,
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
+/* Built-in ip4 unicast rx feature path definition */
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_inacl, static) = {
+ .node_name = "ip4-inacl",
+ .runs_before = {"ip4-source-check-via-rx", 0},
+ .feature_index = &ip4_main.ip4_unicast_rx_feature_check_access,
+};
+
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
+ .node_name = "ip4-source-check-via-rx",
+ .runs_before = {"ip4-source-check-via-any", 0},
+ .feature_index =
+ &ip4_main.ip4_unicast_rx_feature_source_reachable_via_rx,
+};
+
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
+ .node_name = "ip4-source-check-via-any",
+ .runs_before = {"ipsec-input-ip4", 0},
+ .feature_index =
+ &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
+};
+
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
+ .node_name = "ipsec-input-ip4",
+ .runs_before = {"vpath-input-ip4", 0},
+ .feature_index = &ip4_main.ip4_unicast_rx_feature_ipsec,
+};
+
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_vpath, static) = {
+ .node_name = "vpath-input-ip4",
+ .runs_before = {"ip4-lookup", 0},
+ .feature_index = &ip4_main.ip4_unicast_rx_feature_vpath,
+};
+
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = {
+ .node_name = "ip4-lookup",
+ .runs_before = {0}, /* not before any other features */
+ .feature_index = &ip4_main.ip4_unicast_rx_feature_lookup,
+};
+
+/* Built-in ip4 multicast rx feature path definition */
+VNET_IP4_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
+ .node_name = "vpath-input-ip4",
+ .runs_before = {"ip4-lookup-multicast", 0},
+ .feature_index = &ip4_main.ip4_multicast_rx_feature_vpath,
+};
+
+VNET_IP4_MULTICAST_FEATURE_INIT (ip4_lookup_mc, static) = {
+ .node_name = "ip4-lookup-multicast",
+ .runs_before = {0}, /* not before any other features */
+ .feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
+};
+
+static char * feature_start_nodes[] =
+ { "ip4-input", "ip4-input-no-checksum"};
+
+static clib_error_t *
+ip4_feature_init (vlib_main_t * vm, ip4_main_t * im)
+{
+ ip_lookup_main_t * lm = &im->lookup_main;
+ clib_error_t * error;
+ vnet_cast_t cast;
+
+ for (cast = 0; cast < VNET_N_CAST; cast++)
+ {
+ ip_config_main_t * cm = &lm->rx_config_mains[cast];
+ vnet_config_main_t * vcm = &cm->config_main;
+
+ if ((error = ip_feature_init_cast (vm, cm, vcm,
+ feature_start_nodes,
+ ARRAY_LEN(feature_start_nodes),
+ cast,
+ 1 /* is_ip4 */)))
+ return error;
+ }
+ return 0;
+}
+
static clib_error_t *
ip4_sw_interface_add_del (vnet_main_t * vnm,
u32 sw_if_index,
@@ -1293,57 +1370,31 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
ip4_main_t * im = &ip4_main;
ip_lookup_main_t * lm = &im->lookup_main;
u32 ci, cast;
+ u32 feature_index;
for (cast = 0; cast < VNET_N_CAST; cast++)
{
ip_config_main_t * cm = &lm->rx_config_mains[cast];
vnet_config_main_t * vcm = &cm->config_main;
- if (! vcm->node_index_by_feature_index)
- {
- if (cast == VNET_UNICAST)
- {
- static char * start_nodes[] = { "ip4-input", "ip4-input-no-checksum", };
- static char * feature_nodes[] = {
- [IP4_RX_FEATURE_CHECK_ACCESS] = "ip4-inacl",
- [IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_RX] = "ip4-source-check-via-rx",
- [IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_ANY] = "ip4-source-check-via-any",
- [IP4_RX_FEATURE_IPSEC] = "ipsec-input-ip4",
- [IP4_RX_FEATURE_VPATH] = "vpath-input-ip4",
- [IP4_RX_FEATURE_LOOKUP] = "ip4-lookup",
- };
-
- vnet_config_init (vm, vcm,
- start_nodes, ARRAY_LEN (start_nodes),
- feature_nodes, ARRAY_LEN (feature_nodes));
- }
- else
- {
- static char * start_nodes[] = { "ip4-input", "ip4-input-no-checksum", };
- static char * feature_nodes[] = {
- [IP4_RX_FEATURE_VPATH] = "vpath-input-ip4",
- [IP4_RX_FEATURE_LOOKUP] = "ip4-lookup-multicast",
- };
-
- vnet_config_init (vm, vcm,
- start_nodes, ARRAY_LEN (start_nodes),
- feature_nodes, ARRAY_LEN (feature_nodes));
- }
- }
-
vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
ci = cm->config_index_by_sw_if_index[sw_if_index];
+ if (cast == VNET_UNICAST)
+ feature_index = im->ip4_unicast_rx_feature_lookup;
+ else
+ feature_index = im->ip4_multicast_rx_feature_lookup;
+
if (is_add)
ci = vnet_config_add_feature (vm, vcm,
ci,
- IP4_RX_FEATURE_LOOKUP,
+ feature_index,
/* config data */ 0,
/* # bytes of config data */ 0);
else
ci = vnet_config_del_feature (vm, vcm,
ci,
- IP4_RX_FEATURE_LOOKUP,
+ feature_index,
/* config data */ 0,
/* # bytes of config data */ 0);
@@ -1450,6 +1501,8 @@ ip4_lookup_init (vlib_main_t * vm)
"ip4 arp");
}
+ ip4_feature_init (vm, im);
+
return 0;
}
diff --git a/vnet/vnet/ip/ip4_input.c b/vnet/vnet/ip/ip4_input.c
index 606342501a0..5b2b42ded13 100644
--- a/vnet/vnet/ip/ip4_input.c
+++ b/vnet/vnet/ip/ip4_input.c
@@ -150,18 +150,18 @@ ip4_input_inline (vlib_main_t * vm,
cm0 = lm->rx_config_mains + cast0;
cm1 = lm->rx_config_mains + cast1;
- vnet_buffer (p0)->ip.current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
- vnet_buffer (p1)->ip.current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
+ p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
+ p1->current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
vnet_get_config_data (&cm0->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
/* # bytes of config data */ 0);
vnet_get_config_data (&cm1->config_main,
- &vnet_buffer (p1)->ip.current_config_index,
+ &p1->current_config_index,
&next1,
/* # bytes of config data */ 0);
@@ -264,10 +264,10 @@ ip4_input_inline (vlib_main_t * vm,
cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
cm0 = lm->rx_config_mains + cast0;
- vnet_buffer (p0)->ip.current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
+ p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
vnet_get_config_data (&cm0->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
/* # bytes of config data */ 0);
diff --git a/vnet/vnet/ip/ip4_source_check.c b/vnet/vnet/ip/ip4_source_check.c
index 11e6678ed2b..64b1e0abe25 100644
--- a/vnet/vnet/ip/ip4_source_check.c
+++ b/vnet/vnet/ip/ip4_source_check.c
@@ -142,11 +142,11 @@ ip4_source_check_inline (vlib_main_t * vm,
ip1 = vlib_buffer_get_current (p1);
c0 = vnet_get_config_data (&cm->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
sizeof (c0[0]));
c1 = vnet_get_config_data (&cm->config_main,
- &vnet_buffer (p1)->ip.current_config_index,
+ &p1->current_config_index,
&next1,
sizeof (c1[0]));
@@ -223,7 +223,7 @@ ip4_source_check_inline (vlib_main_t * vm,
ip0 = vlib_buffer_get_current (p0);
c0 = vnet_get_config_data (&cm->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
sizeof (c0[0]));
@@ -329,7 +329,7 @@ set_ip_source_check (vlib_main_t * vm,
clib_error_t * error = 0;
u32 sw_if_index, is_del, ci;
ip4_source_check_config_t config;
- ip4_rx_feature_type_t type;
+ u32 feature_index;
sw_if_index = ~0;
@@ -343,7 +343,7 @@ set_ip_source_check (vlib_main_t * vm,
is_del = 0;
config.no_default_route = 0;
config.fib_index = im->fib_index_by_sw_if_index[sw_if_index];
- type = IP4_RX_FEATURE_SOURCE_CHECK_REACHABLE_VIA_RX;
+ feature_index = im->ip4_unicast_rx_feature_source_reachable_via_rx;
if (unformat (input, "del"))
is_del = 1;
@@ -353,7 +353,7 @@ set_ip_source_check (vlib_main_t * vm,
: vnet_config_add_feature)
(vm, &rx_cm->config_main,
ci,
- type,
+ feature_index,
&config,
sizeof (config));
rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h
index 69e69f2c9cd..3c27db0455b 100644
--- a/vnet/vnet/ip/ip6.h
+++ b/vnet/vnet/ip/ip6.h
@@ -103,33 +103,6 @@ typedef struct {
uword function_opaque;
} ip6_add_del_interface_address_callback_t;
-typedef enum {
- /* First check access list to either permit or deny this
- packet based on classification. */
- IP6_RX_FEATURE_CHECK_ACCESS,
-
- /* RPF check: verify that source address is reachable via
- RX interface or via any interface. */
- IP6_RX_FEATURE_CHECK_SOURCE_REACHABLE_VIA_RX,
- IP6_RX_FEATURE_CHECK_SOURCE_REACHABLE_VIA_ANY,
-
- /* IPSec */
- IP6_RX_FEATURE_IPSEC,
-
- /* Intercept and decap L2TPv3 packets. */
- IP6_RX_FEATURE_L2TPV3,
-
- /* vPath forwarding: won't return to call next feature
- so any feature needed before vPath forwarding must be prior
- to this entry */
- IP6_RX_FEATURE_VPATH,
-
- /* Must be last: perform forwarding lookup. */
- IP6_RX_FEATURE_LOOKUP,
-
- IP6_N_RX_FEATURE,
-} ip6_rx_feature_type_t;
-
typedef struct ip6_main_t {
BVT(clib_bihash) ip6_lookup_table;
@@ -168,6 +141,21 @@ typedef struct ip6_main_t {
u32 lookup_table_nbuckets;
uword lookup_table_size;
+ /* feature path configuration lists */
+ vnet_ip_feature_registration_t * next_uc_feature;
+ vnet_ip_feature_registration_t * next_mc_feature;
+
+ /* Built-in unicast feature path indices, see ip_feature_init_cast(...) */
+ u32 ip6_unicast_rx_feature_check_access;
+ u32 ip6_unicast_rx_feature_ipsec;
+ u32 ip6_unicast_rx_feature_l2tp_decap;
+ u32 ip6_unicast_rx_feature_vpath;
+ u32 ip6_unicast_rx_feature_lookup;
+
+ /* Built-in multicast feature path indices */
+ u32 ip6_multicast_rx_feature_vpath;
+ u32 ip6_multicast_rx_feature_lookup;
+
/* Seed for Jenkins hash used to compute ip6 flow hash. */
u32 flow_hash_seed;
@@ -185,6 +173,30 @@ typedef struct ip6_main_t {
/* Global ip6 main structure. */
extern ip6_main_t ip6_main;
+#define VNET_IP6_UNICAST_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t uc_##x; \
+static void __vnet_add_feature_registration_uc_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_uc_##x (void) \
+{ \
+ ip6_main_t * im = &ip6_main; \
+ uc_##x.next = im->next_uc_feature; \
+ im->next_uc_feature = &uc_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t uc_##x
+
+#define VNET_IP6_MULTICAST_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t mc_##x; \
+static void __vnet_add_feature_registration_mc_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_mc_##x (void) \
+{ \
+ ip6_main_t * im = &ip6_main; \
+ mc_##x.next = im->next_mc_feature; \
+ im->next_mc_feature = &mc_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t mc_##x
+
/* Global ip6 input node. Errors get attached to ip6 input node. */
extern vlib_node_registration_t ip6_input_node;
extern vlib_node_registration_t ip6_rewrite_node;
diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c
index e49d242e6f3..f77b99ef31b 100644
--- a/vnet/vnet/ip/ip6_forward.c
+++ b/vnet/vnet/ip/ip6_forward.c
@@ -1200,6 +1200,75 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm,
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
+/* Built-in ip6 unicast rx feature path definition */
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_inacl, static) = {
+ .node_name = "ip6-inacl",
+ .runs_before = {"ipsec-input-ip6", 0},
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_check_access,
+};
+
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_ipsec, static) = {
+ .node_name = "ipsec-input-ip6",
+ .runs_before = {"l2tp-decap", 0},
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_ipsec,
+};
+
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_l2tp, static) = {
+ .node_name = "l2tp-decap",
+ .runs_before = {"vpath-input-ip6", 0},
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_l2tp_decap,
+};
+
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_vpath, static) = {
+ .node_name = "vpath-input-ip6",
+ .runs_before = {"ip6-lookup", 0},
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_vpath,
+};
+
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_lookup, static) = {
+ .node_name = "ip6-lookup",
+ .runs_before = {0}, /* not before any other features */
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_lookup,
+};
+
+/* Built-in ip6 multicast rx feature path definition (none now) */
+VNET_IP6_MULTICAST_FEATURE_INIT (ip4_vpath_mc, static) = {
+ .node_name = "vpath-input-ip6",
+ .runs_before = {"ip6-lookup", 0},
+ .feature_index = &ip6_main.ip6_multicast_rx_feature_vpath,
+};
+
+VNET_IP6_MULTICAST_FEATURE_INIT (ip6_lookup, static) = {
+ .node_name = "ip6-lookup",
+ .runs_before = {0}, /* not before any other features */
+ .feature_index = &ip6_main.ip6_multicast_rx_feature_lookup,
+};
+
+static char * feature_start_nodes[] =
+ {"ip6-input"};
+
+static clib_error_t *
+ip6_feature_init (vlib_main_t * vm, ip6_main_t * im)
+{
+ ip_lookup_main_t * lm = &im->lookup_main;
+ clib_error_t * error;
+ vnet_cast_t cast;
+
+ for (cast = 0; cast < VNET_N_CAST; cast++)
+ {
+ ip_config_main_t * cm = &lm->rx_config_mains[cast];
+ vnet_config_main_t * vcm = &cm->config_main;
+
+ if ((error = ip_feature_init_cast (vm, cm, vcm,
+ feature_start_nodes,
+ ARRAY_LEN(feature_start_nodes),
+ cast,
+ 0 /* is_ip4 */)))
+ return error;
+ }
+ return 0;
+}
+
clib_error_t *
ip6_sw_interface_add_del (vnet_main_t * vnm,
u32 sw_if_index,
@@ -1209,41 +1278,31 @@ ip6_sw_interface_add_del (vnet_main_t * vnm,
ip6_main_t * im = &ip6_main;
ip_lookup_main_t * lm = &im->lookup_main;
u32 ci, cast;
+ u32 feature_index;
for (cast = 0; cast < VNET_N_CAST; cast++)
{
ip_config_main_t * cm = &lm->rx_config_mains[cast];
vnet_config_main_t * vcm = &cm->config_main;
- /* FIXME multicast. */
- if (! vcm->node_index_by_feature_index)
- {
- char * start_nodes[] = { "ip6-input", };
- char * feature_nodes[] = {
- [IP6_RX_FEATURE_CHECK_ACCESS] = "ip6-inacl",
- [IP6_RX_FEATURE_IPSEC] = "ipsec-input-ip6",
- [IP6_RX_FEATURE_L2TPV3] = "l2tp-decap",
- [IP6_RX_FEATURE_VPATH] = "vpath-input-ip6",
- [IP6_RX_FEATURE_LOOKUP] = "ip6-lookup",
- };
- vnet_config_init (vm, vcm,
- start_nodes, ARRAY_LEN (start_nodes),
- feature_nodes, ARRAY_LEN (feature_nodes));
- }
-
vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
ci = cm->config_index_by_sw_if_index[sw_if_index];
+ if (cast == VNET_UNICAST)
+ feature_index = im->ip6_unicast_rx_feature_lookup;
+ else
+ feature_index = im->ip6_multicast_rx_feature_lookup;
+
if (is_add)
ci = vnet_config_add_feature (vm, vcm,
ci,
- IP6_RX_FEATURE_LOOKUP,
+ feature_index,
/* config data */ 0,
/* # bytes of config data */ 0);
else
ci = vnet_config_del_feature (vm, vcm,
ci,
- IP6_RX_FEATURE_LOOKUP,
+ feature_index,
/* config data */ 0,
/* # bytes of config data */ 0);
@@ -2857,6 +2916,8 @@ ip6_lookup_init (vlib_main_t * vm)
"ip6 neighbor discovery");
}
+ ip6_feature_init (vm, im);
+
return 0;
}
diff --git a/vnet/vnet/ip/ip6_input.c b/vnet/vnet/ip/ip6_input.c
index 2042cbd7813..7b5470dc553 100644
--- a/vnet/vnet/ip/ip6_input.c
+++ b/vnet/vnet/ip/ip6_input.c
@@ -149,18 +149,18 @@ ip6_input (vlib_main_t * vm,
cm0 = lm->rx_config_mains + cast0;
cm1 = lm->rx_config_mains + cast1;
- vnet_buffer (p0)->ip.current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
- vnet_buffer (p1)->ip.current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
+ p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
+ p1->current_config_index = vec_elt (cm1->config_index_by_sw_if_index, sw_if_index1);
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
vnet_get_config_data (&cm0->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
/* # bytes of config data */ 0);
vnet_get_config_data (&cm1->config_main,
- &vnet_buffer (p1)->ip.current_config_index,
+ &p1->current_config_index,
&next1,
/* # bytes of config data */ 0);
@@ -234,11 +234,11 @@ ip6_input (vlib_main_t * vm,
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
cm0 = lm->rx_config_mains + cast0;
- vnet_buffer (p0)->ip.current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
+ p0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index, sw_if_index0);
vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
vnet_get_config_data (&cm0->config_main,
- &vnet_buffer (p0)->ip.current_config_index,
+ &p0->current_config_index,
&next0,
/* # bytes of config data */ 0);
diff --git a/vnet/vnet/ip/ip_feature_registration.c b/vnet/vnet/ip/ip_feature_registration.c
new file mode 100644
index 00000000000..02699c4f087
--- /dev/null
+++ b/vnet/vnet/ip/ip_feature_registration.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015 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/vnet.h>
+#include <vnet/ip/ip.h>
+
+static int comma_split (u8 *s, u8 **a, u8 **b)
+{
+ *a = s;
+
+ while (*s && *s != ',')
+ s++;
+
+ if (*s == ',')
+ *s = 0;
+ else
+ return 1;
+
+ *b = (u8 *) (s+1);
+ return 0;
+}
+
+clib_error_t *
+ip_feature_init_cast (vlib_main_t * vm,
+ ip_config_main_t * cm,
+ vnet_config_main_t * vcm,
+ char **feature_start_nodes,
+ int num_feature_start_nodes,
+ vnet_cast_t cast,
+ int is_ip4)
+{
+ uword * index_by_name;
+ uword * reg_by_index;
+ u8 ** node_names = 0;
+ u8 * node_name;
+ char ** these_constraints;
+ char * this_constraint_c;
+ u8 ** constraints = 0;
+ u8 * constraint_tuple;
+ u8 * this_constraint;
+ u8 ** orig, ** closure;
+ uword * p;
+ int i, j, k;
+ u8 * a_name, * b_name;
+ int a_index, b_index;
+ int n_features;
+ u32 * result = 0;
+ vnet_ip_feature_registration_t * this_reg, * first_reg;
+ char ** feature_nodes = 0;
+ hash_pair_t * hp;
+ u8 ** keys_to_delete = 0;
+ ip4_main_t * im4 = &ip4_main;
+ ip6_main_t * im6 = &ip6_main;
+
+ index_by_name = hash_create_string (0, sizeof (uword));
+ reg_by_index = hash_create (0, sizeof (uword));
+
+ if (cast == VNET_UNICAST)
+ {
+ if (is_ip4)
+ first_reg = im4->next_uc_feature;
+ else
+ first_reg = im6->next_uc_feature;
+ }
+ else
+ {
+ if (is_ip4)
+ first_reg = im4->next_mc_feature;
+ else
+ first_reg = im6->next_mc_feature;
+ }
+
+ this_reg = first_reg;
+
+ /* pass 1, collect feature node names, construct a before b pairs */
+ while (this_reg)
+ {
+ node_name = format (0, "%s%c", this_reg->node_name, 0);
+ hash_set (reg_by_index, vec_len(node_names), (uword) this_reg);
+
+ hash_set_mem (index_by_name, node_name, vec_len(node_names));
+
+ vec_add1 (node_names, node_name);
+
+ these_constraints = this_reg->runs_before;
+
+ while (these_constraints [0])
+ {
+ this_constraint_c = these_constraints[0];
+
+ constraint_tuple = format (0, "%s,%s%c", node_name,
+ this_constraint_c, 0);
+ vec_add1 (constraints, constraint_tuple);
+ these_constraints++;
+ }
+ this_reg = this_reg->next;
+ }
+
+ n_features = vec_len (node_names);
+ orig = clib_ptclosure_alloc (n_features);
+
+ for (i = 0; i < vec_len (constraints); i++)
+ {
+ this_constraint = constraints[i];
+
+ if (comma_split (this_constraint, &a_name, &b_name))
+ return clib_error_return (0, "comma_split failed!");
+
+ p = hash_get_mem (index_by_name, a_name);
+ if (p == 0)
+ return clib_error_return (0, "feature node '%s' not found", a_name);
+ a_index = p[0];
+
+ p = hash_get_mem (index_by_name, b_name);
+ if (p == 0)
+ return clib_error_return (0, "feature node '%s' not found", b_name);
+ b_index = p[0];
+
+ /* add a before b to the original set of constraints */
+ orig[a_index][b_index] = 1;
+ vec_free (this_constraint);
+ }
+
+ /* Compute the positive transitive closure of the original constraints */
+ closure = clib_ptclosure (orig);
+
+ /* Compute a partial order across feature nodes, if one exists. */
+ again:
+ for (i = 0; i < n_features; i++)
+ {
+ for (j = 0; j < n_features; j++)
+ {
+ if (closure[i][j])
+ goto item_constrained;
+ }
+ /* Item i can be output */
+ vec_add1 (result, i);
+ {
+ for (k = 0; k < n_features; k++)
+ closure [k][i] = 0;
+ /*
+ * Add a "Magic" a before a constraint.
+ * This means we'll never output it again
+ */
+ closure [i][i] = 1;
+ goto again;
+ }
+ item_constrained:
+ ;
+ }
+
+ /* see if we got a partial order... */
+ if (vec_len (result) != n_features)
+ return clib_error_return (0, "ip4_feature_init_cast (cast=%d), no PO!");
+
+ /*
+ * We win.
+ * Bind the index variables, and output the feature node name vector
+ * using the partial order we just computed. Result is in stack
+ * order, because the entry with the fewest constraints (e.g. none)
+ * is output first, etc.
+ */
+
+ for (i = n_features-1; i >= 0; i--)
+ {
+ p = hash_get (reg_by_index, result[i]);
+ ASSERT (p != 0);
+ this_reg = (vnet_ip_feature_registration_t *)p[0];
+ *this_reg->feature_index = n_features - (i+1);
+ vec_add1 (feature_nodes, this_reg->node_name);
+ }
+
+ /* Set up the config infrastructure */
+ vnet_config_init (vm, vcm,
+ feature_start_nodes,
+ num_feature_start_nodes,
+ feature_nodes,
+ vec_len(feature_nodes));
+
+ /* Finally, clean up all the shit we allocated */
+ hash_foreach_pair (hp, index_by_name,
+ ({
+ vec_add1 (keys_to_delete, (u8 *)hp->key);
+ }));
+ hash_free (index_by_name);
+ for (i = 0; i < vec_len(keys_to_delete); i++)
+ vec_free (keys_to_delete[i]);
+ vec_free (keys_to_delete);
+ hash_free (reg_by_index);
+ vec_free (result);
+ clib_ptclosure_free (orig);
+ clib_ptclosure_free (closure);
+ return 0;
+}
+
diff --git a/vnet/vnet/ip/ip_feature_registration.h b/vnet/vnet/ip/ip_feature_registration.h
new file mode 100644
index 00000000000..da2a0055b2f
--- /dev/null
+++ b/vnet/vnet/ip/ip_feature_registration.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 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 included_ip_feature_registration_h
+#define included_ip_feature_registration_h
+
+typedef struct _vnet_ip_feature_registration {
+ struct _vnet_ip_feature_registration * next;
+ char * node_name;
+ u32 * feature_index;
+ char * runs_before[];
+} vnet_ip_feature_registration_t;
+
+clib_error_t *
+ip_feature_init_cast (vlib_main_t * vm,
+ ip_config_main_t * cm,
+ vnet_config_main_t * vcm,
+ char **feature_start_nodes,
+ int num_feature_start_nodes,
+ vnet_cast_t cast,
+ int is_ip4);
+
+#endif /* included_ip_feature_registration_h */
diff --git a/vnet/vnet/ip/ip_input_acl.c b/vnet/vnet/ip/ip_input_acl.c
index fcf8eeabc7b..eaf7f34eec5 100644
--- a/vnet/vnet/ip/ip_input_acl.c
+++ b/vnet/vnet/ip/ip_input_acl.c
@@ -232,7 +232,7 @@ ip_inacl_inline (vlib_main_t * vm,
e0 = 0;
t0 = 0;
vnet_get_config_data (am->vnet_config_main[tid],
- &vnet_buffer(b0)->ip.current_config_index,
+ &b0->current_config_index,
&next0,
/* # bytes of config data */ 0);
diff --git a/vnet/vnet/ipsec/ipsec.c b/vnet/vnet/ipsec/ipsec.c
index ea077d0a127..1c9d57b1a24 100644
--- a/vnet/vnet/ipsec/ipsec.c
+++ b/vnet/vnet/ipsec/ipsec.c
@@ -73,7 +73,7 @@ ipsec_set_interface_spd(vlib_main_t * vm, u32 sw_if_index, u32 spd_id, int is_ad
ci = (is_add ? vnet_config_add_feature : vnet_config_del_feature)
(vm, &rx_cm->config_main,
ci,
- IP4_RX_FEATURE_IPSEC,
+ ip4_main.ip4_unicast_rx_feature_ipsec,
&config,
sizeof (config));
rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
@@ -87,7 +87,7 @@ ipsec_set_interface_spd(vlib_main_t * vm, u32 sw_if_index, u32 spd_id, int is_ad
ci = (is_add ? vnet_config_add_feature : vnet_config_del_feature)
(vm, &rx_cm->config_main,
ci,
- IP6_RX_FEATURE_IPSEC,
+ ip6_main.ip6_unicast_rx_feature_ipsec,
&config,
sizeof (config));
rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
diff --git a/vnet/vnet/ipsec/ipsec_input.c b/vnet/vnet/ipsec/ipsec_input.c
index 09acd106cae..e7011177a33 100644
--- a/vnet/vnet/ipsec/ipsec_input.c
+++ b/vnet/vnet/ipsec/ipsec_input.c
@@ -212,7 +212,7 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
c0 = vnet_get_config_data (&cm->config_main,
- &vnet_buffer (b0)->ip.current_config_index,
+ &b0->current_config_index,
&next0, sizeof (c0[0]));
spd0 = pool_elt_at_index(im->spds, c0->spd_index);
@@ -335,7 +335,7 @@ ipsec_input_ip6_node_fn (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
c0 = vnet_get_config_data (&cm->config_main,
- &vnet_buffer (b0)->ip.current_config_index,
+ &b0->current_config_index,
&next0, sizeof (c0[0]));
spd0 = pool_elt_at_index(im->spds, c0->spd_index);
diff --git a/vnet/vnet/l2tp/decap.c b/vnet/vnet/l2tp/decap.c
index 5f0d05c097f..8b9761a60c1 100644
--- a/vnet/vnet/l2tp/decap.c
+++ b/vnet/vnet/l2tp/decap.c
@@ -198,7 +198,7 @@ static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
ip6_l2tpv3_config_t * c0;
vnet_get_config_data (&cm->config_main,
- &vnet_buffer (b)->ip.current_config_index,
+ &b->current_config_index,
&next_index,
sizeof (c0[0]));
}
diff --git a/vnet/vnet/l2tp/l2tp.c b/vnet/vnet/l2tp/l2tp.c
index 7dfbe156c46..db4b4f5a29b 100644
--- a/vnet/vnet/l2tp/l2tp.c
+++ b/vnet/vnet/l2tp/l2tp.c
@@ -577,12 +577,12 @@ int l2tpv3_interface_enable_disable (vnet_main_t * vnm,
ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
u32 ci;
ip6_l2tpv3_config_t config;
- ip6_rx_feature_type_t type;
+ u32 feature_index;
if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
- type = IP6_RX_FEATURE_L2TPV3;
+ feature_index = im->ip6_unicast_rx_feature_ipsec;
ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
ci = (enable_disable
@@ -590,7 +590,7 @@ int l2tpv3_interface_enable_disable (vnet_main_t * vnm,
: vnet_config_del_feature)
(vlib_get_main(), &rx_cm->config_main,
ci,
- type,
+ feature_index,
&config,
sizeof (config));
rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
diff --git a/vnet/vnet/misc.c b/vnet/vnet/misc.c
index 6effe6eae3e..9dbed8d8609 100644
--- a/vnet/vnet/misc.c
+++ b/vnet/vnet/misc.c
@@ -76,6 +76,15 @@ vnet_main_init (vlib_main_t * vm)
if ((error = vlib_call_init_function (vm, vnet_interface_init)))
return error;
+ if ((error = vlib_call_init_function (vm, ip_main_init)))
+ return error;
+
+ if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
+ return error;
+
+ if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
+ return error;
+
vnm->vlib_main = vm;
hw_if_index = vnet_register_interface