summaryrefslogtreecommitdiffstats
path: root/vnet
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2016-08-17 11:54:30 -0400
committerKeith Burns <alagalah@gmail.com>2016-08-19 18:42:04 +0000
commit5331c72daa9f7d345915a865df898cff652289ac (patch)
tree91f6d8fa0fa32f4052790d83d97c1402158ef67e /vnet
parent5e15c91b6c2b5fbd7f989c5dc4edde506d254926 (diff)
VPP-337 Add per interface IN filtering
- ip post-rewrite feature subgraph arc support Change-Id: Ia4b07197463021ade916326231af246e2559a290 Signed-off-by: Dave Barach <dave@barachs.net> Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
Diffstat (limited to 'vnet')
-rw-r--r--vnet/vnet/classify/input_acl.c2
-rw-r--r--vnet/vnet/classify/policer_classify.c2
-rw-r--r--vnet/vnet/ip/ip.h6
-rw-r--r--vnet/vnet/ip/ip4.h41
-rw-r--r--vnet/vnet/ip/ip4_forward.c199
-rw-r--r--vnet/vnet/ip/ip4_input.c18
-rw-r--r--vnet/vnet/ip/ip4_source_and_port_range_check.c263
-rw-r--r--vnet/vnet/ip/ip4_source_check.c4
-rw-r--r--vnet/vnet/ip/ip6.h19
-rw-r--r--vnet/vnet/ip/ip6_forward.c181
-rw-r--r--vnet/vnet/ip/ip6_input.c12
-rw-r--r--vnet/vnet/ip/ip_feature_registration.c46
-rw-r--r--vnet/vnet/ip/ip_feature_registration.h5
-rw-r--r--vnet/vnet/ip/ip_init.c22
-rw-r--r--vnet/vnet/ip/lookup.h10
-rw-r--r--vnet/vnet/ipsec/ipsec.c4
-rw-r--r--vnet/vnet/ipsec/ipsec_input.c4
-rw-r--r--vnet/vnet/l2tp/decap.c3
-rw-r--r--vnet/vnet/l2tp/l2tp.c3
-rw-r--r--vnet/vnet/vnet.h7
20 files changed, 665 insertions, 186 deletions
diff --git a/vnet/vnet/classify/input_acl.c b/vnet/vnet/classify/input_acl.c
index fb9a2a46b08..91ae06852d1 100644
--- a/vnet/vnet/classify/input_acl.c
+++ b/vnet/vnet/classify/input_acl.c
@@ -49,7 +49,7 @@ vnet_inacl_ip_feature_enable (vlib_main_t * vnm,
ftype = ip6_main.ip6_unicast_rx_feature_check_access;
}
- ipcm = &lm->rx_config_mains[VNET_UNICAST];
+ ipcm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
ci = ipcm->config_index_by_sw_if_index[sw_if_index];
ci = ((feature_enable)
diff --git a/vnet/vnet/classify/policer_classify.c b/vnet/vnet/classify/policer_classify.c
index c4c44849e1d..e4580a204bb 100644
--- a/vnet/vnet/classify/policer_classify.c
+++ b/vnet/vnet/classify/policer_classify.c
@@ -44,7 +44,7 @@ vnet_policer_classify_feature_enable (vlib_main_t * vnm,
ftype = ip6_main.ip6_unicast_rx_feature_policer_classify;
}
- ipcm = &lm->rx_config_mains[VNET_UNICAST];
+ ipcm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
ci = ipcm->config_index_by_sw_if_index[sw_if_index];
ci = (feature_enable ? vnet_config_add_feature : vnet_config_del_feature)
diff --git a/vnet/vnet/ip/ip.h b/vnet/vnet/ip/ip.h
index c9a82930a67..c5882c58dff 100644
--- a/vnet/vnet/ip/ip.h
+++ b/vnet/vnet/ip/ip.h
@@ -217,4 +217,10 @@ void ip_del_all_interface_addresses (vlib_main_t *vm, u32 sw_if_index);
extern vlib_node_registration_t ip4_inacl_node;
extern vlib_node_registration_t ip6_inacl_node;
+void
+vnet_config_update_tx_feature_count (ip_lookup_main_t * lm,
+ ip_config_main_t * tx_cm,
+ u32 sw_if_index,
+ int is_add);
+
#endif /* included_ip_main_h */
diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h
index 9a54300b257..fc74e9d61ed 100644
--- a/vnet/vnet/ip/ip4.h
+++ b/vnet/vnet/ip/ip4.h
@@ -141,31 +141,38 @@ typedef struct ip4_main_t {
/** Feature path configuration lists */
vnet_ip_feature_registration_t * next_uc_feature;
vnet_ip_feature_registration_t * next_mc_feature;
+ vnet_ip_feature_registration_t * next_tx_feature;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_check_access;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_source_reachable_via_rx;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_source_reachable_via_any;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_policer_classify;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_ipsec;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_vpath;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_lookup;
- /** Built-in unicast feature path indice, see @ref ip_feature_init_cast() */
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
u32 ip4_unicast_rx_feature_source_and_port_range_check;
- /** Built-in multicast feature path indices */
+ /** Built-in multicast feature path index */
u32 ip4_multicast_rx_feature_vpath;
- /** Built-in multicast feature path indices */
+ /** Built-in multicast feature path index */
u32 ip4_multicast_rx_feature_lookup;
+ /** Built-in unicast feature path index, see @ref ip_feature_init_cast() */
+ u32 ip4_unicast_tx_feature_source_and_port_range_check;
+
+ /** Built-in tx feature path index */
+ u32 ip4_tx_feature_interface_output;
+
/** Save results for show command */
- char ** feature_nodes[VNET_N_CAST];
+ char ** feature_nodes[VNET_N_IP_FEAT];
/** Seed for Jenkins hash used to compute ip4 flow hash. */
u32 flow_hash_seed;
@@ -209,6 +216,18 @@ static void __vnet_add_feature_registration_mc_##x (void) \
} \
__VA_ARGS__ vnet_ip_feature_registration_t mc_##x
+#define VNET_IP4_TX_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t tx_##x; \
+static void __vnet_add_feature_registration_tx_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_tx_##x (void) \
+{ \
+ ip4_main_t * im = &ip4_main; \
+ tx_##x.next = im->next_tx_feature; \
+ im->next_tx_feature = &tx_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t tx_##x
+
/** Global ip4 input node. Errors get attached to ip4 input node. */
extern vlib_node_registration_t ip4_input_node;
diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c
index 4b019bce8de..dd9fce4592b 100644
--- a/vnet/vnet/ip/ip4_forward.c
+++ b/vnet/vnet/ip/ip4_forward.c
@@ -1387,91 +1387,127 @@ 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},
+ .runs_before = ORDER_CONSTRAINTS {"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},
+ .runs_before = ORDER_CONSTRAINTS {"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 = {"ip4-policer-classify", 0},
+ .runs_before = ORDER_CONSTRAINTS {"ip4-policer-classify", 0},
.feature_index =
&ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
};
-VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_and_port_range_check, static) = {
- .node_name = "ip4-source-and-port-range-check",
- .runs_before = {"ip4-policer-classify", 0},
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) = {
+ .node_name = "ip4-source-and-port-range-check-rx",
+ .runs_before = ORDER_CONSTRAINTS {"ip4-policer-classify", 0},
.feature_index =
&ip4_main.ip4_unicast_rx_feature_source_and_port_range_check,
};
VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
.node_name = "ip4-policer-classify",
- .runs_before = {"ipsec-input-ip4", 0},
+ .runs_before = ORDER_CONSTRAINTS {"ipsec-input-ip4", 0},
.feature_index =
&ip4_main.ip4_unicast_rx_feature_policer_classify,
};
VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
.node_name = "ipsec-input-ip4",
- .runs_before = {"vpath-input-ip4", 0},
+ .runs_before = ORDER_CONSTRAINTS {"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},
+ .runs_before = ORDER_CONSTRAINTS {"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 */
+ .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},
+ .runs_before = ORDER_CONSTRAINTS {"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 */
+ .runs_before = 0, /* not before any other features */
.feature_index = &ip4_main.ip4_multicast_rx_feature_lookup,
};
-static char * feature_start_nodes[] =
+static char * rx_feature_start_nodes[] =
{ "ip4-input", "ip4-input-no-checksum"};
+static char * tx_feature_start_nodes[] =
+{ "ip4-rewrite-transit"};
+
+/* Source and port-range check ip4 tx feature path definition */
+VNET_IP4_TX_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) = {
+ .node_name = "ip4-source-and-port-range-check-tx",
+ .runs_before = ORDER_CONSTRAINTS {"interface-output", 0},
+ .feature_index =
+ &ip4_main.ip4_unicast_tx_feature_source_and_port_range_check,
+
+};
+
+/* Built-in ip4 tx feature path definition */
+VNET_IP4_TX_FEATURE_INIT (interface_output, static) = {
+ .node_name = "interface-output",
+ .runs_before = 0, /* not before any other features */
+ .feature_index = &ip4_main.ip4_tx_feature_interface_output,
+};
+
+
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;
+ ip_config_main_t * cm;
+ vnet_config_main_t * vcm;
+ char **feature_start_nodes;
+ int feature_start_len;
- for (cast = 0; cast < VNET_N_CAST; cast++)
+ for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
{
- ip_config_main_t * cm = &lm->rx_config_mains[cast];
- vnet_config_main_t * vcm = &cm->config_main;
+ cm = &lm->feature_config_mains[cast];
+ vcm = &cm->config_main;
+ if (cast < VNET_IP_TX_FEAT)
+ {
+ feature_start_nodes = rx_feature_start_nodes;
+ feature_start_len = ARRAY_LEN(rx_feature_start_nodes);
+ }
+ else
+ {
+ feature_start_nodes = tx_feature_start_nodes;
+ feature_start_len = ARRAY_LEN(tx_feature_start_nodes);
+ }
+
if ((error = ip_feature_init_cast (vm, cm, vcm,
feature_start_nodes,
- ARRAY_LEN(feature_start_nodes),
+ feature_start_len,
cast,
1 /* is_ip4 */)))
return error;
}
+
return 0;
}
@@ -1486,21 +1522,23 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
u32 ci, cast;
u32 feature_index;
- for (cast = 0; cast < VNET_N_CAST; cast++)
+ for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
{
- ip_config_main_t * cm = &lm->rx_config_mains[cast];
+ ip_config_main_t * cm = &lm->feature_config_mains[cast];
vnet_config_main_t * vcm = &cm->config_main;
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)
+ if (cast == VNET_IP_RX_UNICAST_FEAT)
feature_index = im->ip4_unicast_rx_feature_lookup;
- else
+ else if (cast == VNET_IP_RX_MULTICAST_FEAT)
feature_index = im->ip4_multicast_rx_feature_lookup;
+ else
+ feature_index = im->ip4_tx_feature_interface_output;
if (is_add)
- ci = vnet_config_add_feature (vm, vcm,
+ ci = vnet_config_add_feature (vm, vcm,
ci,
feature_index,
/* config data */ 0,
@@ -1513,6 +1551,9 @@ ip4_sw_interface_add_del (vnet_main_t * vnm,
/* # bytes of config data */ 0);
cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ /*
+ * note: do not update the tx feature count here.
+ */
}
return /* no error */ 0;
@@ -1533,7 +1574,7 @@ VLIB_REGISTER_NODE (ip4_lookup_node) = {
.next_nodes = IP4_LOOKUP_NEXT_NODES,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
static uword
ip4_indirect (vlib_main_t * vm,
@@ -1555,7 +1596,7 @@ VLIB_REGISTER_NODE (ip4_indirect_node) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_indirect_node, ip4_indirect);
/* Global IP4 main. */
@@ -1825,7 +1866,7 @@ VLIB_REGISTER_NODE (ip4_drop_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
VLIB_REGISTER_NODE (ip4_punt_node,static) = {
.function = ip4_punt,
@@ -1840,7 +1881,7 @@ VLIB_REGISTER_NODE (ip4_punt_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
VLIB_REGISTER_NODE (ip4_miss_node,static) = {
.function = ip4_miss,
@@ -1855,7 +1896,7 @@ VLIB_REGISTER_NODE (ip4_miss_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_miss_node, ip4_miss);
/* Compute TCP/UDP/ICMP4 checksum in software. */
u16
@@ -2299,7 +2340,7 @@ VLIB_REGISTER_NODE (ip4_local_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
void ip4_register_protocol (u32 protocol, u32 node_index)
{
@@ -2644,6 +2685,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
u32 n_left_from, n_left_to_next, * to_next, next_index;
vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
+ ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
@@ -2661,6 +2703,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
u32 next0_override, next1_override;
+ u32 tx_sw_if_index0, tx_sw_if_index1;
if (rewrite_for_locally_received_packets)
next0_override = next1_override = 0;
@@ -2826,17 +2869,44 @@ ip4_rewrite_inline (vlib_main_t * vm,
{
p0->current_data -= rw_len0;
p0->current_length += rw_len0;
- p0->error = error_node->errors[error0];
+ tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
vnet_buffer (p0)->sw_if_index[VLIB_TX] =
- adj0[0].rewrite_header.sw_if_index;
+ tx_sw_if_index0;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index0)))
+ {
+ p0->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index0);
+ vnet_get_config_data (&cm->config_main,
+ &p0->current_config_index,
+ &next0,
+ /* # bytes of config data */ 0);
+ }
}
if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
{
p1->current_data -= rw_len1;
p1->current_length += rw_len1;
- p1->error = error_node->errors[error1];
+
+ tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
vnet_buffer (p1)->sw_if_index[VLIB_TX] =
- adj1[0].rewrite_header.sw_if_index;
+ tx_sw_if_index1;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index1)))
+ {
+ p1->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index1);
+ vnet_get_config_data (&cm->config_main,
+ &p1->current_config_index,
+ &next1,
+ /* # bytes of config data */ 0);
+ }
}
/* Guess we are only writing on simple Ethernet header. */
@@ -2856,6 +2926,7 @@ ip4_rewrite_inline (vlib_main_t * vm,
ip4_header_t * ip0;
u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
u32 next0_override;
+ u32 tx_sw_if_index0;
if (rewrite_for_locally_received_packets)
next0_override = 0;
@@ -2957,10 +3028,23 @@ ip4_rewrite_inline (vlib_main_t * vm,
{
p0->current_data -= rw_len0;
p0->current_length += rw_len0;
+ tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] =
- adj0[0].rewrite_header.sw_if_index;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index0)))
+ {
+ p0->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index0);
+ vnet_get_config_data (&cm->config_main,
+ &p0->current_config_index,
+ &next0,
+ /* # bytes of config data */ 0);
+ }
}
if (rewrite_for_locally_received_packets)
@@ -3084,7 +3168,7 @@ VLIB_REGISTER_NODE (ip4_rewrite_node) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite_transit);
VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
.function = ip4_rewrite_local,
@@ -3098,7 +3182,7 @@ VLIB_REGISTER_NODE (ip4_rewrite_local_node) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_local_node, ip4_rewrite_local);
static clib_error_t *
add_del_interface_table (vlib_main_t * vm,
@@ -3377,7 +3461,7 @@ VLIB_REGISTER_NODE (ip4_lookup_multicast_node,static) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast)
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node, ip4_lookup_multicast);
VLIB_REGISTER_NODE (ip4_multicast_node,static) = {
.function = ip4_drop,
@@ -3602,3 +3686,44 @@ VLIB_CLI_COMMAND (set_ip_classify_command, static) = {
.function = set_ip_classify_command_fn,
};
+
+#define TEST_CODE 1
+#if TEST_CODE > 0
+
+static clib_error_t *
+set_interface_output_feature_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ u32 sw_if_index = ~0;
+ int is_add = 1;
+ ip4_main_t * im = &ip4_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+ ;
+ else if (unformat (input, "del"))
+ is_add = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "unknown interface `%U'",
+ format_unformat_error, input);
+
+ lm->tx_sw_if_has_ip_output_features =
+ clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index, is_add);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (set_interface_output_feature, static) = {
+ .path = "set interface output feature",
+ .function = set_interface_output_feature_command_fn,
+ .short_help = "set interface output feature <intfc>",
+};
+#endif /* TEST_CODE */
diff --git a/vnet/vnet/ip/ip4_input.c b/vnet/vnet/ip/ip4_input.c
index 96a68661376..2de2d4756b3 100644
--- a/vnet/vnet/ip/ip4_input.c
+++ b/vnet/vnet/ip/ip4_input.c
@@ -144,11 +144,11 @@ ip4_input_inline (vlib_main_t * vm,
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
- cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
- cast1 = ip4_address_is_multicast (&ip1->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
+ cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+ cast1 = ip4_address_is_multicast (&ip1->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
- cm0 = lm->rx_config_mains + cast0;
- cm1 = lm->rx_config_mains + cast1;
+ cm0 = lm->feature_config_mains + cast0;
+ cm1 = lm->feature_config_mains + cast1;
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);
@@ -195,8 +195,8 @@ ip4_input_inline (vlib_main_t * vm,
error1 = ip4_get_fragment_offset (ip1) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
/* TTL < 1? Drop it. */
- error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
- error1 = (ip1->ttl < 1 && cast1 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error1;
+ error0 = (ip0->ttl < 1 && cast0 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error0;
+ error1 = (ip1->ttl < 1 && cast1 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error1;
/* Verify lengths. */
ip_len0 = clib_net_to_host_u16 (ip0->length);
@@ -262,8 +262,8 @@ ip4_input_inline (vlib_main_t * vm,
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
- cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
- cm0 = lm->rx_config_mains + cast0;
+ cast0 = ip4_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+ cm0 = lm->feature_config_mains + cast0;
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,
@@ -294,7 +294,7 @@ ip4_input_inline (vlib_main_t * vm,
error0 = ip4_get_fragment_offset (ip0) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
/* TTL < 1? Drop it. */
- error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
+ error0 = (ip0->ttl < 1 && cast0 == VNET_IP_RX_UNICAST_FEAT) ? IP4_ERROR_TIME_EXPIRED : error0;
/* Verify lengths. */
ip_len0 = clib_net_to_host_u16 (ip0->length);
diff --git a/vnet/vnet/ip/ip4_source_and_port_range_check.c b/vnet/vnet/ip/ip4_source_and_port_range_check.c
index 00faddf0fb3..ebfa767d8f0 100644
--- a/vnet/vnet/ip/ip4_source_and_port_range_check.c
+++ b/vnet/vnet/ip/ip4_source_and_port_range_check.c
@@ -16,7 +16,8 @@
#include <vnet/ip/ip_source_and_port_range_check.h>
-vlib_node_registration_t ip4_source_port_and_range_check;
+vlib_node_registration_t ip4_source_port_and_range_check_rx;
+vlib_node_registration_t ip4_source_port_and_range_check_tx;
#define foreach_ip4_source_and_port_range_check_error \
_(CHECK_FAIL, "ip4 source and port range check bad packets") \
@@ -42,7 +43,7 @@ typedef struct
u32 bypass;
u32 is_tcp;
ip4_address_t src_addr;
- u16 dst_port;
+ u16 port;
u32 fib_index;
} ip4_source_and_port_range_check_trace_t;
@@ -59,7 +60,7 @@ format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
else
s = format (s, "fib %d src ip %U %s dst port %d: %s",
t->fib_index, format_ip4_address, &t->src_addr,
- t->is_tcp ? "TCP" : "UDP", (u32) t->dst_port,
+ t->is_tcp ? "TCP" : "UDP", (u32) t->port,
(t->pass == 1) ? "PASS" : "FAIL");
return s;
}
@@ -127,12 +128,15 @@ check_adj_port_range_x1 (ip_adjacency_t * adj, u16 dst_port, u32 next)
}
always_inline uword
- ip4_source_and_port_range_check_inline
- (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
+ip4_source_and_port_range_check_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame, int is_tx)
{
ip4_main_t *im = &ip4_main;
ip_lookup_main_t *lm = &im->lookup_main;
- ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *rx_cm =
+ &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+ ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
u32 n_left_from, *from, *to_next;
u32 next_index;
vlib_node_runtime_t *error_node = node;
@@ -196,12 +200,24 @@ always_inline uword
ip0 = vlib_buffer_get_current (b0);
ip1 = vlib_buffer_get_current (b1);
- c0 = vnet_get_config_data (&cm->config_main,
- &b0->current_config_index,
- &next0, sizeof (c0[0]));
- c1 = vnet_get_config_data (&cm->config_main,
- &b1->current_config_index,
- &next1, sizeof (c1[0]));
+ if (is_tx)
+ {
+ c0 = vnet_get_config_data (&tx_cm->config_main,
+ &b0->current_config_index,
+ &next0, sizeof (c0[0]));
+ c1 = vnet_get_config_data (&tx_cm->config_main,
+ &b1->current_config_index,
+ &next1, sizeof (c1[0]));
+ }
+ else
+ {
+ c0 = vnet_get_config_data (&rx_cm->config_main,
+ &b0->current_config_index,
+ &next0, sizeof (c0[0]));
+ c1 = vnet_get_config_data (&rx_cm->config_main,
+ &b1->current_config_index,
+ &next1, sizeof (c1[0]));
+ }
/* we can't use the default VRF here... */
for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
@@ -210,12 +226,28 @@ always_inline uword
}
- if (ip0->protocol == IP_PROTOCOL_UDP)
- fib_index0 =
- c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
- if (ip0->protocol == IP_PROTOCOL_TCP)
- fib_index0 =
- c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ if (is_tx)
+ {
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+ if (ip0->protocol == IP_PROTOCOL_TCP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+ }
+ else
+ {
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+ if (ip0->protocol == IP_PROTOCOL_TCP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ }
if (PREDICT_TRUE (fib_index0 != ~0))
{
@@ -239,19 +271,35 @@ always_inline uword
adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
- &ip0->
- src_address, 0
+ &ip0->src_address,
+ 0
/* use dflt rt */
));
adj0 = ip_get_adjacency (lm, adj_index0);
}
- if (ip1->protocol == IP_PROTOCOL_UDP)
- fib_index1 =
- c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
- if (ip1->protocol == IP_PROTOCOL_TCP)
- fib_index1 =
- c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ if (is_tx)
+ {
+ if (ip1->protocol == IP_PROTOCOL_UDP)
+ fib_index1 =
+ c1->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+ if (ip1->protocol == IP_PROTOCOL_TCP)
+ fib_index1 =
+ c1->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+ }
+ else
+ {
+ if (ip1->protocol == IP_PROTOCOL_UDP)
+ fib_index1 =
+ c1->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+ if (ip1->protocol == IP_PROTOCOL_TCP)
+ fib_index1 =
+ c1->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ }
if (PREDICT_TRUE (fib_index1 != ~0))
{
@@ -275,8 +323,7 @@ always_inline uword
adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
- &ip1->
- src_address,
+ &ip1->src_address,
0));
adj1 = ip_get_adjacency (lm, adj_index1);
}
@@ -331,7 +378,7 @@ always_inline uword
t->bypass = pass0;
t->fib_index = fib_index0;
t->src_addr.as_u32 = ip0->src_address.as_u32;
- t->dst_port = (pass0 == 0) ?
+ t->port = (pass0 == 0) ?
clib_net_to_host_u16 (udp0->dst_port) : 0;
t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
}
@@ -345,7 +392,7 @@ always_inline uword
t->bypass = pass1;
t->fib_index = fib_index1;
t->src_addr.as_u32 = ip1->src_address.as_u32;
- t->dst_port = (pass1 == 0) ?
+ t->port = (pass1 == 0) ?
clib_net_to_host_u16 (udp1->dst_port) : 0;
t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
}
@@ -379,11 +426,23 @@ always_inline uword
vec_elt (im->fib_index_by_sw_if_index,
vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+ if (is_tx)
+ vlib_buffer_advance (b0, sizeof (ethernet_header_t));
+
ip0 = vlib_buffer_get_current (b0);
- c0 = vnet_get_config_data
- (&cm->config_main, &b0->current_config_index,
- &next0, sizeof (c0[0]));
+ if (is_tx)
+ {
+ c0 = vnet_get_config_data
+ (&tx_cm->config_main, &b0->current_config_index,
+ &next0, sizeof (c0[0]));
+ }
+ else
+ {
+ c0 = vnet_get_config_data
+ (&rx_cm->config_main, &b0->current_config_index,
+ &next0, sizeof (c0[0]));
+ }
/* we can't use the default VRF here... */
for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
@@ -392,12 +451,28 @@ always_inline uword
}
- if (ip0->protocol == IP_PROTOCOL_UDP)
- fib_index0 =
- c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
- if (ip0->protocol == IP_PROTOCOL_TCP)
- fib_index0 =
- c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ if (is_tx)
+ {
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
+ if (ip0->protocol == IP_PROTOCOL_TCP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
+ }
+ else
+ {
+ if (ip0->protocol == IP_PROTOCOL_UDP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
+ if (ip0->protocol == IP_PROTOCOL_TCP)
+ fib_index0 =
+ c0->fib_index
+ [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
+ }
if (fib_index0 != ~0)
{
@@ -458,11 +533,14 @@ always_inline uword
t->bypass = pass0;
t->fib_index = fib_index0;
t->src_addr.as_u32 = ip0->src_address.as_u32;
- t->dst_port = (pass0 == 0) ?
+ t->port = (pass0 == 0) ?
clib_net_to_host_u16 (udp0->dst_port) : 0;
t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
}
+ if (is_tx)
+ vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
+
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
@@ -471,24 +549,63 @@ always_inline uword
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
- vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
- IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
- good_packets);
+ if (is_tx)
+ vlib_node_increment_counter (vm, ip4_source_port_and_range_check_tx.index,
+ IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
+ good_packets);
+ else
+ vlib_node_increment_counter (vm, ip4_source_port_and_range_check_rx.index,
+ IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
+ good_packets);
return frame->n_vectors;
}
static uword
-ip4_source_and_port_range_check (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+ip4_source_and_port_range_check_rx (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
- return ip4_source_and_port_range_check_inline (vm, node, frame);
+ return ip4_source_and_port_range_check_inline (vm, node, frame,
+ 0 /* !is_tx */ );
}
+static uword
+ip4_source_and_port_range_check_tx (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return ip4_source_and_port_range_check_inline (vm, node, frame,
+ 1 /* is_tx */ );
+}
+
+/* Note: Calling same function for both RX and TX nodes
+ as always checking dst_port, although
+ if this changes can easily make new function
+*/
+
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
- .function = ip4_source_and_port_range_check,
- .name = "ip4-source-and-port-range-check",
+VLIB_REGISTER_NODE (ip4_source_port_and_range_check_rx) = {
+ .function = ip4_source_and_port_range_check_rx,
+ .name = "ip4-source-and-port-range-check-rx",
+ .vector_size = sizeof (u32),
+
+ .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
+ .error_strings = ip4_source_and_port_range_check_error_strings,
+
+ .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
+ .next_nodes = {
+ [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
+ },
+
+ .format_buffer = format_ip4_header,
+ .format_trace = format_ip4_source_and_port_range_check_trace,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip4_source_port_and_range_check_tx) = {
+ .function = ip4_source_and_port_range_check_tx,
+ .name = "ip4-source-and-port-range-check-tx",
.vector_size = sizeof (u32),
.n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
@@ -511,7 +628,9 @@ set_ip_source_and_port_range_check (vlib_main_t * vm,
{
ip4_main_t *im = &ip4_main;
ip_lookup_main_t *lm = &im->lookup_main;
- ip_config_main_t *rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *rx_cm =
+ &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
+ ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
u32 ci;
ip_source_and_port_range_check_config_t config;
u32 feature_index;
@@ -523,17 +642,41 @@ set_ip_source_and_port_range_check (vlib_main_t * vm,
config.fib_index[i] = fib_index[i];
}
- feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
+ /* For OUT we are in the RX path */
+ if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] != ~0) ||
+ (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] != ~0))
+ {
+ feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
+
+ vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
+
+ ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
+ ci = (is_add
+ ? vnet_config_add_feature
+ : vnet_config_del_feature)
+ (vm, &rx_cm->config_main, ci, feature_index, &config,
+ sizeof (config));
+ rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ }
+
+ /* For IN we are in the TX path */
+ if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] != ~0) ||
+ (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] != ~0))
+ {
+ feature_index = im->ip4_unicast_tx_feature_source_and_port_range_check;
- vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
+ vec_validate (tx_cm->config_index_by_sw_if_index, sw_if_index);
- ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
- ci = (is_add
- ? vnet_config_add_feature
- : vnet_config_del_feature)
- (vm, &rx_cm->config_main, ci, feature_index, &config, sizeof (config));
- rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ ci = tx_cm->config_index_by_sw_if_index[sw_if_index];
+ ci = (is_add
+ ? vnet_config_add_feature
+ : vnet_config_del_feature)
+ (vm, &tx_cm->config_main, ci, feature_index, &config,
+ sizeof (config));
+ tx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ vnet_config_update_tx_feature_count (lm, tx_cm, sw_if_index, is_add);
+ }
return rv;
}
@@ -1006,7 +1149,7 @@ VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
.path = "set ip source-and-port-range-check",
.function = ip_source_and_port_range_check_command_fn,
.short_help =
- "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn>-<nn> tcp-vrf <id>] [vrf <id>] [del]",
+ "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn> - <nn>] [vrf <id>] [del]",
};
/* *INDENT-ON* */
diff --git a/vnet/vnet/ip/ip4_source_check.c b/vnet/vnet/ip/ip4_source_check.c
index 64b1e0abe25..1f8e7214ff1 100644
--- a/vnet/vnet/ip/ip4_source_check.c
+++ b/vnet/vnet/ip/ip4_source_check.c
@@ -82,7 +82,7 @@ ip4_source_check_inline (vlib_main_t * vm,
{
ip4_main_t * im = &ip4_main;
ip_lookup_main_t * lm = &im->lookup_main;
- ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
u32 n_left_from, * from, * to_next;
u32 next_index;
vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
@@ -325,7 +325,7 @@ set_ip_source_check (vlib_main_t * vm,
vnet_main_t * vnm = vnet_get_main();
ip4_main_t * im = &ip4_main;
ip_lookup_main_t * lm = &im->lookup_main;
- ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t * rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
clib_error_t * error = 0;
u32 sw_if_index, is_del, ci;
ip4_source_check_config_t config;
diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h
index 3d6c9f422e8..0d5d8d04bf8 100644
--- a/vnet/vnet/ip/ip6.h
+++ b/vnet/vnet/ip/ip6.h
@@ -145,6 +145,7 @@ typedef struct ip6_main_t {
/* feature path configuration lists */
vnet_ip_feature_registration_t * next_uc_feature;
vnet_ip_feature_registration_t * next_mc_feature;
+ vnet_ip_feature_registration_t * next_tx_feature;
/* Built-in unicast feature path indices, see ip_feature_init_cast(...) */
u32 ip6_unicast_rx_feature_check_access;
@@ -157,9 +158,12 @@ typedef struct ip6_main_t {
/* Built-in multicast feature path indices */
u32 ip6_multicast_rx_feature_vpath;
u32 ip6_multicast_rx_feature_lookup;
+
+ /* Built-in tx feature path index */
+ u32 ip6_tx_feature_interface_output;
/* Save results for show command */
- char ** feature_nodes[VNET_N_CAST];
+ char ** feature_nodes[VNET_N_IP_FEAT];
/* Seed for Jenkins hash used to compute ip6 flow hash. */
u32 flow_hash_seed;
@@ -202,6 +206,19 @@ static void __vnet_add_feature_registration_mc_##x (void) \
} \
__VA_ARGS__ vnet_ip_feature_registration_t mc_##x
+#define VNET_IP6_TX_FEATURE_INIT(x,...) \
+ __VA_ARGS__ vnet_ip_feature_registration_t tx_##x; \
+static void __vnet_add_feature_registration_tx_##x (void) \
+ __attribute__((__constructor__)) ; \
+static void __vnet_add_feature_registration_tx_##x (void) \
+{ \
+ ip6_main_t * im = &ip6_main; \
+ tx_##x.next = im->next_tx_feature; \
+ im->next_tx_feature = &tx_##x; \
+} \
+__VA_ARGS__ vnet_ip_feature_registration_t tx_##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 1e4afa8d0c0..f79acf74d7b 100644
--- a/vnet/vnet/ip/ip6_forward.c
+++ b/vnet/vnet/ip/ip6_forward.c
@@ -1252,71 +1252,96 @@ 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 = {"ip6-policer-classify", 0},
+ .runs_before = ORDER_CONSTRAINTS {"ip6-policer-classify", 0},
.feature_index = &ip6_main.ip6_unicast_rx_feature_check_access,
};
VNET_IP6_UNICAST_FEATURE_INIT (ip6_policer_classify, static) = {
.node_name = "ip6-policer-classify",
- .runs_before = {"ipsec-input-ip6", 0},
+ .runs_before = ORDER_CONSTRAINTS {"ipsec-input-ip6", 0},
.feature_index = &ip6_main.ip6_unicast_rx_feature_policer_classify,
};
VNET_IP6_UNICAST_FEATURE_INIT (ip6_ipsec, static) = {
.node_name = "ipsec-input-ip6",
- .runs_before = {"l2tp-decap", 0},
+ .runs_before = ORDER_CONSTRAINTS {"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},
+ .runs_before = ORDER_CONSTRAINTS {"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},
+ .runs_before = ORDER_CONSTRAINTS {"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 */
+ .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) = {
+VNET_IP6_MULTICAST_FEATURE_INIT (ip6_vpath_mc, static) = {
.node_name = "vpath-input-ip6",
- .runs_before = {"ip6-lookup", 0},
+ .runs_before = ORDER_CONSTRAINTS {"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 */
+ .runs_before = 0, /* not before any other features */
.feature_index = &ip6_main.ip6_multicast_rx_feature_lookup,
};
-static char * feature_start_nodes[] =
+static char * rx_feature_start_nodes[] =
{"ip6-input"};
+static char * tx_feature_start_nodes[] =
+ {"ip6-rewrite"};
+
+/* Built-in ip4 tx feature path definition */
+VNET_IP6_TX_FEATURE_INIT (interface_output, static) = {
+ .node_name = "interface-output",
+ .runs_before = 0, /* not before any other features */
+ .feature_index = &ip6_main.ip6_tx_feature_interface_output,
+};
+
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;
+ ip_config_main_t * cm;
+ vnet_config_main_t * vcm;
+ char **feature_start_nodes;
+ int feature_start_len;
- for (cast = 0; cast < VNET_N_CAST; cast++)
+ for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
{
- ip_config_main_t * cm = &lm->rx_config_mains[cast];
- vnet_config_main_t * vcm = &cm->config_main;
+ cm = &lm->feature_config_mains[cast];
+ vcm = &cm->config_main;
+ if (cast < VNET_IP_TX_FEAT)
+ {
+ feature_start_nodes = rx_feature_start_nodes;
+ feature_start_len = ARRAY_LEN(rx_feature_start_nodes);
+ }
+ else
+ {
+ feature_start_nodes = tx_feature_start_nodes;
+ feature_start_len = ARRAY_LEN(tx_feature_start_nodes);
+ }
+
if ((error = ip_feature_init_cast (vm, cm, vcm,
feature_start_nodes,
- ARRAY_LEN(feature_start_nodes),
+ feature_start_len,
cast,
0 /* is_ip4 */)))
return error;
@@ -1335,18 +1360,20 @@ ip6_sw_interface_add_del (vnet_main_t * vnm,
u32 ci, cast;
u32 feature_index;
- for (cast = 0; cast < VNET_N_CAST; cast++)
+ for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
{
- ip_config_main_t * cm = &lm->rx_config_mains[cast];
+ ip_config_main_t * cm = &lm->feature_config_mains[cast];
vnet_config_main_t * vcm = &cm->config_main;
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)
+ if (cast == VNET_IP_RX_UNICAST_FEAT)
feature_index = im->ip6_unicast_rx_feature_lookup;
- else
+ else if (cast == VNET_IP_RX_MULTICAST_FEAT)
feature_index = im->ip6_multicast_rx_feature_lookup;
+ else
+ feature_index = im->ip6_tx_feature_interface_output;
if (is_add)
ci = vnet_config_add_feature (vm, vcm,
@@ -1362,6 +1389,9 @@ ip6_sw_interface_add_del (vnet_main_t * vnm,
/* # bytes of config data */ 0);
cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ /*
+ * note: do not update the tx feature count here.
+ */
}
return /* no error */ 0;
}
@@ -1389,7 +1419,7 @@ VLIB_REGISTER_NODE (ip6_lookup_node) = {
.next_nodes = IP6_LOOKUP_NEXT_NODES,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
static uword
ip6_indirect (vlib_main_t * vm,
@@ -1409,7 +1439,7 @@ VLIB_REGISTER_NODE (ip6_indirect_node) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_indirect_node, ip6_indirect)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_indirect_node, ip6_indirect);
typedef struct {
/* Adjacency taken. */
@@ -1617,7 +1647,7 @@ VLIB_REGISTER_NODE (ip6_drop_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
VLIB_REGISTER_NODE (ip6_punt_node,static) = {
.function = ip6_punt,
@@ -1632,7 +1662,7 @@ VLIB_REGISTER_NODE (ip6_punt_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
VLIB_REGISTER_NODE (ip6_miss_node,static) = {
.function = ip6_miss,
@@ -1647,7 +1677,7 @@ VLIB_REGISTER_NODE (ip6_miss_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_miss_node, ip6_miss)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_miss_node, ip6_miss);
VLIB_REGISTER_NODE (ip6_multicast_node,static) = {
.function = ip6_drop,
@@ -2027,7 +2057,7 @@ VLIB_REGISTER_NODE (ip6_local_node,static) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
void ip6_register_protocol (u32 protocol, u32 node_index)
{
@@ -2346,6 +2376,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
u32 n_left_from, n_left_to_next, * to_next, next_index;
vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_input_node.index);
vlib_rx_or_tx_t adj_rx_tx = rewrite_for_locally_received_packets ? VLIB_RX : VLIB_TX;
+ ip_config_main_t * cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
@@ -2362,6 +2393,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
ip6_header_t * ip0, * ip1;
u32 pi0, rw_len0, next0, error0, adj_index0;
u32 pi1, rw_len1, next1, error1, adj_index1;
+ u32 tx_sw_if_index0, tx_sw_if_index1;
/* Prefetch next iteration. */
{
@@ -2485,18 +2517,44 @@ ip6_rewrite_inline (vlib_main_t * vm,
p0->current_data -= rw_len0;
p0->current_length += rw_len0;
+ tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
vnet_buffer (p0)->sw_if_index[VLIB_TX] =
- adj0[0].rewrite_header.sw_if_index;
- next0 = adj0[0].rewrite_header.next_index;
+ tx_sw_if_index0;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index0)))
+ {
+ p0->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index0);
+ vnet_get_config_data (&cm->config_main,
+ &p0->current_config_index,
+ &next0,
+ /* # bytes of config data */ 0);
+ }
}
if (PREDICT_TRUE(error1 == IP6_ERROR_NONE))
{
p1->current_data -= rw_len1;
p1->current_length += rw_len1;
- vnet_buffer (p1)->sw_if_index[VLIB_TX] =
- adj1[0].rewrite_header.sw_if_index;
- next1 = adj1[0].rewrite_header.next_index;
+ tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
+ vnet_buffer (p1)->sw_if_index[VLIB_TX] =
+ tx_sw_if_index1;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index1)))
+ {
+ p1->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index1);
+ vnet_get_config_data (&cm->config_main,
+ &p1->current_config_index,
+ &next1,
+ /* # bytes of config data */ 0);
+ }
}
/* Guess we are only writing on simple Ethernet header. */
@@ -2516,6 +2574,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
ip6_header_t * ip0;
u32 pi0, rw_len0;
u32 adj_index0, next0, error0;
+ u32 tx_sw_if_index0;
pi0 = to_next[0] = from[0];
@@ -2589,9 +2648,23 @@ ip6_rewrite_inline (vlib_main_t * vm,
p0->current_data -= rw_len0;
p0->current_length += rw_len0;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] =
- adj0[0].rewrite_header.sw_if_index;
+ tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
+
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
next0 = adj0[0].rewrite_header.next_index;
+
+ if (PREDICT_FALSE
+ (clib_bitmap_get (lm->tx_sw_if_has_ip_output_features,
+ tx_sw_if_index0)))
+ {
+ p0->current_config_index =
+ vec_elt (cm->config_index_by_sw_if_index,
+ tx_sw_if_index0);
+ vnet_get_config_data (&cm->config_main,
+ &p0->current_config_index,
+ &next0,
+ /* # bytes of config data */ 0);
+ }
}
p0->error = error_node->errors[error0];
@@ -2648,7 +2721,7 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) = {
},
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite_transit)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite_transit);
VLIB_REGISTER_NODE (ip6_rewrite_local_node) = {
.function = ip6_rewrite_local,
@@ -2662,7 +2735,7 @@ VLIB_REGISTER_NODE (ip6_rewrite_local_node) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_local_node, ip6_rewrite_local)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_local_node, ip6_rewrite_local);
/*
* Hop-by-Hop handling
@@ -2884,7 +2957,7 @@ VLIB_REGISTER_NODE (ip6_hop_by_hop_node) = {
.n_next_nodes = 0,
};
-VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop)
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
static clib_error_t *
ip6_hop_by_hop_init (vlib_main_t * vm)
@@ -3328,3 +3401,43 @@ ip6_config (vlib_main_t * vm, unformat_input_t * input)
VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
+#define TEST_CODE 1
+#if TEST_CODE > 0
+
+static clib_error_t *
+set_interface_ip6_output_feature_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ u32 sw_if_index = ~0;
+ int is_add = 1;
+ ip6_main_t * im = &ip6_main;
+ ip_lookup_main_t * lm = &im->lookup_main;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+ ;
+ else if (unformat (input, "del"))
+ is_add = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "unknown interface `%U'",
+ format_unformat_error, input);
+
+ lm->tx_sw_if_has_ip_output_features =
+ clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index, is_add);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (set_interface_ip6_output_feature, static) = {
+ .path = "set interface ip6 output feature",
+ .function = set_interface_ip6_output_feature_command_fn,
+ .short_help = "set interface output feature <intfc>",
+};
+#endif /* TEST_CODE */
diff --git a/vnet/vnet/ip/ip6_input.c b/vnet/vnet/ip/ip6_input.c
index 05929c55884..15791245176 100644
--- a/vnet/vnet/ip/ip6_input.c
+++ b/vnet/vnet/ip/ip6_input.c
@@ -143,11 +143,11 @@ ip6_input (vlib_main_t * vm,
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
- cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
- cast1 = ip6_address_is_multicast (&ip1->dst_address) ? VNET_MULTICAST : VNET_UNICAST;
+ cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+ cast1 = ip6_address_is_multicast (&ip1->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
- cm0 = lm->rx_config_mains + cast0;
- cm1 = lm->rx_config_mains + cast1;
+ cm0 = lm->feature_config_mains + cast0;
+ cm1 = lm->feature_config_mains + cast1;
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);
@@ -232,8 +232,8 @@ ip6_input (vlib_main_t * vm,
ip0 = vlib_buffer_get_current (p0);
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;
+ cast0 = ip6_address_is_multicast (&ip0->dst_address) ? VNET_IP_RX_MULTICAST_FEAT : VNET_IP_RX_UNICAST_FEAT;
+ cm0 = lm->feature_config_mains + cast0;
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;
diff --git a/vnet/vnet/ip/ip_feature_registration.c b/vnet/vnet/ip/ip_feature_registration.c
index 5f0d58ea25d..72deee41004 100644
--- a/vnet/vnet/ip/ip_feature_registration.c
+++ b/vnet/vnet/ip/ip_feature_registration.c
@@ -57,7 +57,7 @@ ip_feature_init_cast (vlib_main_t * vm,
int a_index, b_index;
int n_features;
u32 * result = 0;
- vnet_ip_feature_registration_t * this_reg, * first_reg;
+ vnet_ip_feature_registration_t * this_reg, * first_reg = 0;
char ** feature_nodes = 0;
hash_pair_t * hp;
u8 ** keys_to_delete = 0;
@@ -67,20 +67,28 @@ ip_feature_init_cast (vlib_main_t * vm,
index_by_name = hash_create_string (0, sizeof (uword));
reg_by_index = hash_create (0, sizeof (uword));
- if (cast == VNET_UNICAST)
+ if (cast == VNET_IP_RX_UNICAST_FEAT)
{
if (is_ip4)
first_reg = im4->next_uc_feature;
else
first_reg = im6->next_uc_feature;
}
- else
+ else if (cast == VNET_IP_RX_MULTICAST_FEAT)
{
if (is_ip4)
first_reg = im4->next_mc_feature;
else
first_reg = im6->next_mc_feature;
+ }
+ else if (cast == VNET_IP_TX_FEAT)
+ {
+ if (is_ip4)
+ first_reg = im4->next_tx_feature;
+ else
+ first_reg = im6->next_tx_feature;
}
+
this_reg = first_reg;
@@ -95,8 +103,7 @@ ip_feature_init_cast (vlib_main_t * vm,
vec_add1 (node_names, node_name);
these_constraints = this_reg->runs_before;
-
- while (these_constraints [0])
+ while (these_constraints && these_constraints [0])
{
this_constraint_c = these_constraints[0];
@@ -105,6 +112,19 @@ ip_feature_init_cast (vlib_main_t * vm,
vec_add1 (constraints, constraint_tuple);
these_constraints++;
}
+
+ these_constraints = this_reg->runs_after;
+ while (these_constraints && these_constraints [0])
+ {
+ this_constraint_c = these_constraints[0];
+
+ constraint_tuple = format (0, "%s,%s%c",
+ this_constraint_c,
+ node_name, 0);
+ vec_add1 (constraints, constraint_tuple);
+ these_constraints++;
+ }
+
this_reg = this_reg->next;
}
@@ -220,10 +240,12 @@ ip_feature_init_cast (vlib_main_t * vm,
}
#define foreach_af_cast \
-_(4, VNET_UNICAST, "ip4 unicast") \
-_(4, VNET_MULTICAST, "ip4 multicast") \
-_(6, VNET_UNICAST, "ip6 unicast") \
-_(6, VNET_MULTICAST, "ip6 multicast")
+_(4, VNET_IP_RX_UNICAST_FEAT, "ip4 unicast") \
+_(4, VNET_IP_RX_MULTICAST_FEAT, "ip4 multicast") \
+_(4, VNET_IP_TX_FEAT, "ip4 output") \
+_(6, VNET_IP_RX_UNICAST_FEAT, "ip6 unicast") \
+_(6, VNET_IP_RX_MULTICAST_FEAT, "ip6 multicast") \
+_(6, VNET_IP_TX_FEAT, "ip6 output")
static clib_error_t *
show_ip_features_command_fn (vlib_main_t * vm,
@@ -295,14 +317,14 @@ show_ip_interface_features_command_fn (vlib_main_t * vm,
else
lm = lm6;
- for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
+ for (cast = VNET_IP_RX_UNICAST_FEAT; cast < VNET_N_IP_FEAT; cast++)
{
- cm = lm->rx_config_mains + cast;
+ cm = lm->feature_config_mains + cast;
vcm = &cm->config_main;
vlib_cli_output (vm, "\nipv%s %scast:",
(af == 0) ? "4" : "6",
- cast == VNET_UNICAST ?
+ cast == VNET_IP_RX_UNICAST_FEAT ?
"uni": "multi");
current_config_index = vec_elt (cm->config_index_by_sw_if_index,
diff --git a/vnet/vnet/ip/ip_feature_registration.h b/vnet/vnet/ip/ip_feature_registration.h
index da2a0055b2f..3c78abc0bc8 100644
--- a/vnet/vnet/ip/ip_feature_registration.h
+++ b/vnet/vnet/ip/ip_feature_registration.h
@@ -20,9 +20,12 @@ typedef struct _vnet_ip_feature_registration {
struct _vnet_ip_feature_registration * next;
char * node_name;
u32 * feature_index;
- char * runs_before[];
+ char ** runs_before;
+ char ** runs_after;
} vnet_ip_feature_registration_t;
+#define ORDER_CONSTRAINTS (char*[])
+
clib_error_t *
ip_feature_init_cast (vlib_main_t * vm,
ip_config_main_t * cm,
diff --git a/vnet/vnet/ip/ip_init.c b/vnet/vnet/ip/ip_init.c
index c0c1c9560bc..02da6647be3 100644
--- a/vnet/vnet/ip/ip_init.c
+++ b/vnet/vnet/ip/ip_init.c
@@ -140,3 +140,25 @@ do { \
}
VLIB_INIT_FUNCTION (ip_main_init);
+
+void
+vnet_config_update_tx_feature_count (ip_lookup_main_t * lm,
+ ip_config_main_t * tx_cm,
+ u32 sw_if_index,
+ int is_add)
+{
+ ASSERT (tx_cm == &lm->feature_config_mains[VNET_IP_TX_FEAT]);
+
+ vec_validate (lm->tx_feature_count_by_sw_if_index, sw_if_index);
+
+ lm->tx_feature_count_by_sw_if_index[sw_if_index] += is_add ? 1 : -1;
+
+ ASSERT (lm->tx_feature_count_by_sw_if_index[sw_if_index] >= 0);
+
+ lm->tx_sw_if_has_ip_output_features =
+ clib_bitmap_set (lm->tx_sw_if_has_ip_output_features, sw_if_index,
+ lm->tx_feature_count_by_sw_if_index[sw_if_index] > 0);
+}
+
+
+
diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h
index 2b682d27195..fcd080a4375 100644
--- a/vnet/vnet/ip/lookup.h
+++ b/vnet/vnet/ip/lookup.h
@@ -408,6 +408,12 @@ typedef struct ip_lookup_main_t {
/** Adjacency by signature hash */
uword * adj_index_by_signature;
+ /** any-tx-feature-enabled interface bitmap */
+ uword * tx_sw_if_has_ip_output_features;
+
+ /** count of enabled features, per sw_if_index, to maintain bitmap */
+ i16 * tx_feature_count_by_sw_if_index;
+
/** Temporary vectors for looking up next hops in hash. */
ip_multipath_next_hop_t * next_hop_hash_lookup_key;
ip_multipath_next_hop_t * next_hop_hash_lookup_key_normalized;
@@ -444,8 +450,8 @@ typedef struct ip_lookup_main_t {
/** First table index to use for this interface, ~0 => none */
u32 * classify_table_index_by_sw_if_index;
- /** rx/tx interface/feature configuration. */
- ip_config_main_t rx_config_mains[VNET_N_CAST], tx_config_main;
+ /** rx unicast, multicast, tx interface/feature configuration. */
+ ip_config_main_t feature_config_mains[VNET_N_IP_FEAT];
/** Number of bytes in a fib result. Must be at least
sizeof (uword). First word is always adjacency index. */
diff --git a/vnet/vnet/ipsec/ipsec.c b/vnet/vnet/ipsec/ipsec.c
index 1b3b9ffcc38..3e343834a42 100644
--- a/vnet/vnet/ipsec/ipsec.c
+++ b/vnet/vnet/ipsec/ipsec.c
@@ -78,7 +78,7 @@ ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id,
/* IPv4 */
lm = &ip4_main.lookup_main;
- rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+ rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
@@ -89,7 +89,7 @@ ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id,
/* IPv6 */
lm = &ip6_main.lookup_main;
- rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+ rx_cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
diff --git a/vnet/vnet/ipsec/ipsec_input.c b/vnet/vnet/ipsec/ipsec_input.c
index 8364e226ae1..4087981a3fe 100644
--- a/vnet/vnet/ipsec/ipsec_input.c
+++ b/vnet/vnet/ipsec/ipsec_input.c
@@ -185,7 +185,7 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm,
{
ip4_main_t *i4m = &ip4_main;
ip_lookup_main_t *lm = &i4m->lookup_main;
- ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
u32 n_left_from, *from, next_index, *to_next;
ipsec_main_t *im = &ipsec_main;
@@ -316,7 +316,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip4_node, ipsec_input_ip4_node_fn)
{
ip6_main_t *i6m = &ip6_main;
ip_lookup_main_t *lm = &i6m->lookup_main;
- ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
u32 n_left_from, *from, next_index, *to_next;
ipsec_main_t *im = &ipsec_main;
diff --git a/vnet/vnet/l2tp/decap.c b/vnet/vnet/l2tp/decap.c
index 1b97e712b3b..dfd846aced3 100644
--- a/vnet/vnet/l2tp/decap.c
+++ b/vnet/vnet/l2tp/decap.c
@@ -220,7 +220,8 @@ done:
/* Go to next node on the ip6 configuration chain */
ip6_main_t *im = &ip6_main;
ip_lookup_main_t *lm = &im->lookup_main;
- ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *cm =
+ &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
ip6_l2tpv3_config_t *c0;
vnet_get_config_data (&cm->config_main,
diff --git a/vnet/vnet/l2tp/l2tp.c b/vnet/vnet/l2tp/l2tp.c
index 99443ce4b73..a043483ede4 100644
--- a/vnet/vnet/l2tp/l2tp.c
+++ b/vnet/vnet/l2tp/l2tp.c
@@ -616,7 +616,8 @@ l2tpv3_interface_enable_disable (vnet_main_t * vnm,
{
ip6_main_t *im = &ip6_main;
ip_lookup_main_t *lm = &im->lookup_main;
- ip_config_main_t *rx_cm = &lm->rx_config_mains[VNET_UNICAST];
+ ip_config_main_t *rx_cm =
+ &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
u32 ci;
ip6_l2tpv3_config_t config;
u32 feature_index;
diff --git a/vnet/vnet/vnet.h b/vnet/vnet/vnet.h
index 3bca6bf4f3d..31faef7cbb9 100644
--- a/vnet/vnet/vnet.h
+++ b/vnet/vnet/vnet.h
@@ -44,9 +44,10 @@
typedef enum
{
- VNET_UNICAST,
- VNET_MULTICAST,
- VNET_N_CAST,
+ VNET_IP_RX_UNICAST_FEAT,
+ VNET_IP_RX_MULTICAST_FEAT,
+ VNET_IP_TX_FEAT,
+ VNET_N_IP_FEAT,
} vnet_cast_t;
#include <vnet/unix/pcap.h>