From d65346098daf8967e882d0299679a131769c9be9 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Tue, 14 Jun 2016 18:38:02 -0400 Subject: 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 --- vnet/Makefile.am | 2 + vnet/vnet/buffer.h | 3 - vnet/vnet/classify/input_acl.c | 4 +- vnet/vnet/ip/ip.h | 1 + vnet/vnet/ip/ip4.h | 66 +++++++---- vnet/vnet/ip/ip4_forward.c | 121 +++++++++++++------ vnet/vnet/ip/ip4_input.c | 12 +- vnet/vnet/ip/ip4_source_check.c | 12 +- vnet/vnet/ip/ip6.h | 66 ++++++----- vnet/vnet/ip/ip6_forward.c | 97 ++++++++++++--- vnet/vnet/ip/ip6_input.c | 12 +- vnet/vnet/ip/ip_feature_registration.c | 207 +++++++++++++++++++++++++++++++++ vnet/vnet/ip/ip_feature_registration.h | 35 ++++++ vnet/vnet/ip/ip_input_acl.c | 2 +- vnet/vnet/ipsec/ipsec.c | 4 +- vnet/vnet/ipsec/ipsec_input.c | 4 +- vnet/vnet/l2tp/decap.c | 2 +- vnet/vnet/l2tp/l2tp.c | 6 +- vnet/vnet/misc.c | 9 ++ 19 files changed, 530 insertions(+), 135 deletions(-) create mode 100644 vnet/vnet/ip/ip_feature_registration.c create mode 100644 vnet/vnet/ip/ip_feature_registration.h (limited to 'vnet') 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 #include /* adjacency heap */ +#include #include 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 #include #include +#include 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 +#include + +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 -- cgit 1.2.3-korg