aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2016-06-23 11:27:51 -0400
committerKeith Burns <alagalah@gmail.com>2016-06-23 23:28:41 +0000
commitde393bb76d8c221e1145f62070f51a9ca4191f9f (patch)
tree12cb674fd9b57e1a51f63ed2fcaf40c5a81560a4
parent0f6b7960716d09129bec60fe942a6bed1ef729d5 (diff)
Show command support for ip feature paths
"show ip features" displays all available features, in execution order. "show ip interface features <intfc>" displays all features currently configures on an interface, in execution order. Change-Id: I489bbdb85799a01721ba60b12ffaffcab1e0d1df Signed-off-by: Dave Barach <dave@barachs.net>
-rw-r--r--vnet/vnet/config.c15
-rw-r--r--vnet/vnet/config.h3
-rw-r--r--vnet/vnet/ip/ip4.h3
-rw-r--r--vnet/vnet/ip/ip6.h3
-rw-r--r--vnet/vnet/ip/ip_feature_registration.c126
5 files changed, 147 insertions, 3 deletions
diff --git a/vnet/vnet/config.c b/vnet/vnet/config.c
index d2bcdf7d010..2e056c83738 100644
--- a/vnet/vnet/config.c
+++ b/vnet/vnet/config.c
@@ -276,8 +276,15 @@ u32 vnet_config_add_feature (vlib_main_t * vm,
new = find_config_with_features (vm, cm, new_features);
new->reference_count += 1;
- /* User gets pointer to config string first element (which defines the pool index
- this config string comes from). */
+ /*
+ * User gets pointer to config string first element
+ * (which defines the pool index
+ * this config string comes from).
+ */
+ vec_validate (cm->config_pool_index_by_user_index,
+ new->config_string_heap_index + 1);
+ cm->config_pool_index_by_user_index [new->config_string_heap_index + 1]
+ = new - cm->config_pool;
return new->config_string_heap_index + 1;
}
@@ -327,5 +334,9 @@ u32 vnet_config_del_feature (vlib_main_t * vm,
new = find_config_with_features (vm, cm, new_features);
new->reference_count += 1;
+ vec_validate (cm->config_pool_index_by_user_index,
+ new->config_string_heap_index + 1);
+ cm->config_pool_index_by_user_index [new->config_string_heap_index + 1]
+ = new - cm->config_pool;
return new->config_string_heap_index + 1;
}
diff --git a/vnet/vnet/config.h b/vnet/vnet/config.h
index 1ace30fef88..3d507c7bf34 100644
--- a/vnet/vnet/config.h
+++ b/vnet/vnet/config.h
@@ -95,6 +95,9 @@ typedef struct {
/* Interior feature processing nodes (not including start and end nodes). */
u32 * node_index_by_feature_index;
+ /* vnet_config pool index by user index */
+ u32 * config_pool_index_by_user_index;
+
/* Temporary vector for holding config strings. Used to avoid continually
allocating vectors. */
u32 * config_string_temp;
diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h
index f005522bb7a..b24f18d03e7 100644
--- a/vnet/vnet/ip/ip4.h
+++ b/vnet/vnet/ip/ip4.h
@@ -144,6 +144,9 @@ typedef struct ip4_main_t {
/* Built-in multicast feature path indices */
u32 ip4_multicast_rx_feature_vpath;
u32 ip4_multicast_rx_feature_lookup;
+
+ /* Save results for show command */
+ char ** feature_nodes[VNET_N_CAST];
/* Seed for Jenkins hash used to compute ip4 flow hash. */
u32 flow_hash_seed;
diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h
index 70e32672530..2a386fee214 100644
--- a/vnet/vnet/ip/ip6.h
+++ b/vnet/vnet/ip/ip6.h
@@ -157,6 +157,9 @@ typedef struct ip6_main_t {
u32 ip6_multicast_rx_feature_vpath;
u32 ip6_multicast_rx_feature_lookup;
+ /* Save results for show command */
+ char ** feature_nodes[VNET_N_CAST];
+
/* Seed for Jenkins hash used to compute ip6 flow hash. */
u32 flow_hash_seed;
diff --git a/vnet/vnet/ip/ip_feature_registration.c b/vnet/vnet/ip/ip_feature_registration.c
index 02699c4f087..e100b1e19a3 100644
--- a/vnet/vnet/ip/ip_feature_registration.c
+++ b/vnet/vnet/ip/ip_feature_registration.c
@@ -163,7 +163,9 @@ ip_feature_init_cast (vlib_main_t * vm,
/* 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!");
+ return clib_error_return
+ (0, "ip%s_feature_init_cast (cast=%d), no partial order!",
+ is_ip4 ? "4" : "6", cast);
/*
* We win.
@@ -189,6 +191,12 @@ ip_feature_init_cast (vlib_main_t * vm,
feature_nodes,
vec_len(feature_nodes));
+ /* Save a copy for show command */
+ if (is_ip4)
+ im4->feature_nodes[cast] = feature_nodes;
+ else
+ im6->feature_nodes[cast] = feature_nodes;
+
/* Finally, clean up all the shit we allocated */
hash_foreach_pair (hp, index_by_name,
({
@@ -205,3 +213,119 @@ ip_feature_init_cast (vlib_main_t * vm,
return 0;
}
+#define foreach_af_cast \
+_(4, VNET_UNICAST, "ip4 unicast") \
+_(4, VNET_MULTICAST, "ip4 multicast") \
+_(6, VNET_UNICAST, "ip6 unicast") \
+_(6, VNET_MULTICAST, "ip6 multicast")
+
+static clib_error_t *
+show_ip_features_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ ip4_main_t * im4 = &ip4_main;
+ ip6_main_t * im6 = &ip6_main;
+ int i;
+ char ** features;
+
+ vlib_cli_output (vm, "Available IP feature nodes");
+
+#define _(a,c,s) \
+ do { \
+ features = im##a->feature_nodes[c]; \
+ vlib_cli_output (vm, "%s:", s); \
+ for (i = 0; i < vec_len(features); i++) \
+ vlib_cli_output (vm, " %s\n", features[i]); \
+ } while(0);
+ foreach_af_cast;
+#undef _
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (show_ip_features_command, static) = {
+ .path = "show ip features",
+ .short_help = "show ip features",
+ .function = show_ip_features_command_fn,
+};
+
+static clib_error_t *
+show_ip_interface_features_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ ip4_main_t * im4 = &ip4_main;
+ ip_lookup_main_t * lm4 = &im4->lookup_main;
+ ip6_main_t * im6 = &ip6_main;
+ ip_lookup_main_t * lm6 = &im6->lookup_main;
+
+ ip_lookup_main_t * lm;
+ ip_config_main_t * cm;
+ vnet_config_main_t * vcm;
+ vnet_config_t * cfg;
+ u32 cfg_index;
+ vnet_config_feature_t * feat;
+ vlib_node_t * n;
+ u32 sw_if_index;
+ u32 node_index;
+ u32 current_config_index;
+ int i, af;
+ u32 cast;
+
+ if (! unformat (input, "%U", unformat_vnet_sw_interface,
+ vnm, &sw_if_index))
+ return clib_error_return (0, "Interface not specified...");
+
+ vlib_cli_output (vm, "IP feature paths configured on %U...",
+ format_vnet_sw_if_index_name, vnm, sw_if_index);
+
+
+ for (af = 0; af < 2; af++)
+ {
+ if (af == 0)
+ lm = lm4;
+ else
+ lm = lm6;
+
+ for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
+ {
+ cm = lm->rx_config_mains + cast;
+ vcm = &cm->config_main;
+
+ vlib_cli_output (vm, "\nipv%s %scast:",
+ (af == 0) ? "4" : "6",
+ cast == VNET_UNICAST ?
+ "uni": "multi");
+
+ current_config_index = vec_elt (cm->config_index_by_sw_if_index,
+ sw_if_index);
+
+ ASSERT(current_config_index
+ < vec_len (vcm->config_pool_index_by_user_index));
+
+ cfg_index =
+ vcm->config_pool_index_by_user_index[current_config_index];
+ cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
+
+ for (i = 0; i < vec_len(cfg->features); i++)
+ {
+ feat = cfg->features + i;
+ node_index = feat->node_index;
+ n = vlib_get_node (vm, node_index);
+ vlib_cli_output (vm, " %v", n->name);
+ }
+ }
+ }
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
+ .path = "show ip interface features",
+ .short_help = "show ip interface features <intfc>",
+ .function = show_ip_interface_features_command_fn,
+};
+
+