#include <vppinfra/elog.h>
#include <vnet/ip/ip6_hop_by_hop.h>
+#include <vnet/lib-scv/scv_util.h>
/* Timestamp precision multipliers for seconds, milliseconds, microseconds
* and nanoseconds respectively.
ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
+#define OI_DECAP 100
+
+#define foreach_ip6_hbyh_input_next \
+ _(IP6_REWRITE, "ip6-rewrite") \
+ _(IP6_LOOKUP, "ip6-lookup") \
+ _(IP6_HBYH, "ip6-hop-by-hop")\
+ _(IP6_POP_HBYH, "ip6-pop-hop-by-hop")\
+ _(DROP, "error-drop")
+
+typedef enum {
+#define _(s,n) IP6_HBYH_INPUT_NEXT_##s,
+ foreach_ip6_hbyh_input_next
+#undef _
+ IP6_HBYH_INPUT_N_NEXT,
+} ip6_hbyh_input_next_t;
+
/*
* ip6 hop-by-hop option handling. We push pkts with h-b-h options to
* ip6_hop_by_hop_node_fn from ip6-lookup at a cost of ~2 clocks/pkt in
} time_u64_t;
static inline u8
-fetch_trace_data_size(trace_type)
+fetch_trace_data_size(u8 trace_type)
{
u8 trace_data_size = 0;
return s;
}
+static u8 * format_ioam_pow (u8 * s, va_list * args)
+{
+ ioam_pow_option_t * pow0 = va_arg (*args, ioam_pow_option_t *);
+ u64 random, cumulative;
+ random = cumulative = 0;
+ if (pow0)
+ {
+ random = clib_net_to_host_u64 (pow0->random);
+ cumulative = clib_net_to_host_u64 (pow0->cumulative);
+ }
+
+ s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x",
+ random, cumulative, pow0->reserved_profile_id);
+ return s;
+}
static u8 * format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
{
u32 * elt0;
int elt_index;
u8 type0;
+ ioam_pow_option_t * pow0;
hbh0 = (ip6_hop_by_hop_header_t *)t->option_data;
case HBH_OPTION_TYPE_IOAM_PROOF_OF_WORK:
s = format (s, " POW opt present\n");
+ pow0 = (ioam_pow_option_t *) opt0;
+ s = format (s, " %U\n", format_ioam_pow,pow0);
+
opt0 = (ip6_hop_by_hop_option_t *)
(((u8 *)opt0) + sizeof (ioam_pow_option_t));
break;
vlib_node_registration_t ip6_hop_by_hop_node;
#define foreach_ip6_hop_by_hop_error \
-_(PROCESSED, "Pkts with ip6 hop-by-hop options")
+_(PROCESSED, "Pkts with ip6 hop-by-hop options") \
+_(PROFILE_MISS, "Pkts with ip6 hop-by-hop options but no profile set") \
+_(UNKNOWN_OPTION, "Unknown ip6 hop-by-hop options")
typedef enum {
#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
ip6_hop_by_hop_main_t * hm = &ip6_hop_by_hop_main;
u32 n_left_from, * from, * to_next;
ip_lookup_next_t next_index;
- u32 processed = 0;
+ u32 processed = 0, unknown_opts = 0;
u8 elt_index = 0;
time_u64_t time_u64;
ip6_hop_by_hop_header_t *hbh0;
ip6_hop_by_hop_option_t *opt0, *limit0;
ioam_trace_option_t * trace0;
+ ioam_pow_option_t * pow0;
u32 * elt0;
u8 type0;
-
+ u64 random = 0, cumulative = 0;
+ u8 pow_encap = 0;
+
/* speculatively enqueue b0 to the current next frame */
bi0 = from[0];
to_next[0] = bi0;
break;
case HBH_OPTION_TYPE_IOAM_PROOF_OF_WORK:
+ pow_profile = scv_profile_find(pow_profile_index);
+ if (PREDICT_FALSE(!pow_profile))
+ {
+ vlib_node_increment_counter (vm,
+ ip6_hop_by_hop_node.index,
+ IP6_HOP_BY_HOP_ERROR_PROFILE_MISS, 1);
+
+ opt0 = (ip6_hop_by_hop_option_t *)
+ (((u8 *)opt0) + sizeof (ioam_pow_option_t));
+ break;
+ }
+ pow0 = (ioam_pow_option_t *) opt0;
+ pow_encap = (pow0->random == 0);
+ if (pow_encap)
+ {
+ if (PREDICT_FALSE(total_pkts_using_this_profile >=
+ pow_profile->validity))
+ {
+ /* Choose a new profile */
+ u16 new_profile_index;
+ new_profile_index =
+ scv_get_next_profile_id(vm,
+ pow_profile_index);
+ if (new_profile_index != pow_profile_index)
+ {
+ /* Got a new profile */
+ scv_profile_invalidate(vm, hm,
+ pow_profile_index,
+ pow_encap);
+ pow_profile_index = new_profile_index;
+ pow_profile =
+ scv_profile_find(pow_profile_index);
+ total_pkts_using_this_profile = 0;
+ }
+ else
+ {
+ scv_profile_invalidate(vm, hm,
+ pow_profile_index,
+ pow_encap);
+ }
+ }
+ pow0->reserved_profile_id =
+ pow_profile_index & PROFILE_ID_MASK;
+ total_pkts_using_this_profile++;
+ }
+ else
+ { /* Non encap node */
+ if (PREDICT_FALSE(pow0->reserved_profile_id !=
+ pow_profile_index))
+ {
+ /* New profile announced by encap node. */
+ scv_profile *new_profile = 0;
+ new_profile =
+ scv_profile_find(pow0->reserved_profile_id);
+ if (PREDICT_FALSE(new_profile == 0 ||
+ new_profile->validity == 0))
+ {
+ /* Profile is invalid. Use old profile*/
+ vlib_node_increment_counter (vm,
+ ip6_hop_by_hop_node.index,
+ IP6_HOP_BY_HOP_ERROR_PROFILE_MISS, 1);
+ scv_profile_invalidate(vm, hm,
+ pow0->reserved_profile_id,
+ pow_encap);
+ }
+ else
+ {
+ scv_profile_invalidate(vm, hm,
+ pow_profile_index,
+ pow_encap);
+ pow_profile_index = pow0->reserved_profile_id;
+ pow_profile = new_profile;
+ total_pkts_using_this_profile = 0;
+ }
+ }
+ total_pkts_using_this_profile++;
+ }
+
+ if (pow0->random == 0)
+ {
+ pow0->random = clib_host_to_net_u64(
+ scv_generate_random(pow_profile));
+ pow0->cumulative = 0;
+ }
+ random = clib_net_to_host_u64(pow0->random);
+ cumulative = clib_net_to_host_u64(pow0->cumulative);
+ pow0->cumulative = clib_host_to_net_u64(
+ scv_update_cumulative(pow_profile,
+ cumulative,
+ random));
opt0 = (ip6_hop_by_hop_option_t *)
(((u8 *)opt0) + sizeof (ioam_pow_option_t));
break;
case 0: /* Pad */
opt0 = (ip6_hop_by_hop_option_t *) ((u8 *)opt0) + 1;
goto out0;
+
+ default:
+ opt0 = (ip6_hop_by_hop_option_t *)
+ (((u8 *)opt0) + opt0->length
+ + sizeof (ip6_hop_by_hop_option_t));
+ unknown_opts++;
+ break;
}
}
out0:
-
- /*
- * Since we push pkts here from the h-b-h header imposition code
- * we have to be careful what we wish for...
- */
- next0 = adj0->lookup_next_index != IP_LOOKUP_NEXT_ADD_HOP_BY_HOP ?
- adj0->lookup_next_index : adj0->saved_lookup_next_index;
+ next0 = (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP) ?
+ IP6_HBYH_INPUT_NEXT_IP6_POP_HBYH : IP6_HBYH_INPUT_NEXT_IP6_REWRITE;
+ vnet_buffer(b0)->l2_classify.opaque_index = ~0;
if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
&& (b0->flags & VLIB_BUFFER_IS_TRACED)))
trace_len = trace_len < ARRAY_LEN(t->option_data) ?
trace_len : ARRAY_LEN(t->option_data);
t->trace_len = trace_len;
- t->timestamp_msbs = time_u64.as_u32[1];
- memcpy (t->option_data, hbh0, trace_len);
+ clib_memcpy (t->option_data, hbh0, trace_len);
}
processed++;
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
+ if (PREDICT_FALSE(unknown_opts > 0)) {
+ vlib_node_increment_counter (vm, ip6_hop_by_hop_node.index,
+ IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION, unknown_opts);
+ }
+
vlib_node_increment_counter (vm, ip6_hop_by_hop_node.index,
IP6_HOP_BY_HOP_ERROR_PROCESSED, processed);
return frame->n_vectors;
.n_errors = ARRAY_LEN(ip6_hop_by_hop_error_strings),
.error_strings = ip6_hop_by_hop_error_strings,
- /* See ip/lookup.h */
- .n_next_nodes = IP_LOOKUP_N_NEXT,
+ .n_next_nodes = IP6_HBYH_INPUT_N_NEXT,
.next_nodes = {
- [IP_LOOKUP_NEXT_MISS] = "ip6-miss",
- [IP_LOOKUP_NEXT_DROP] = "ip6-drop",
- [IP_LOOKUP_NEXT_PUNT] = "ip6-punt",
- [IP_LOOKUP_NEXT_LOCAL] = "ip6-local",
- [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor",
- [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite",
- [IP_LOOKUP_NEXT_CLASSIFY] = "ip6-classify",
- [IP_LOOKUP_NEXT_MAP] = "ip6-map",
- [IP_LOOKUP_NEXT_MAP_T] = "ip6-map-t",
- [IP_LOOKUP_NEXT_SIXRD] = "ip6-sixrd",
- /* Next 3 arcs probably never used */
- [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop",
- [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop",
- [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop",
+#define _(s,n) [IP6_HBYH_INPUT_NEXT_##s] = n,
+ foreach_ip6_hbyh_input_next
+#undef _
},
};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop_node_fn)
+
/* The main h-b-h tracer will be invoked, no need to do much here */
typedef struct {
u32 next_index;
hbh0 = (ip6_hop_by_hop_header_t *)(ip0 + 1);
/* $$$ tune, rewrite_length is a multiple of 8 */
- memcpy (hbh0, rewrite, rewrite_length);
+ clib_memcpy (hbh0, rewrite, rewrite_length);
/* Patch the protocol chain, insert the h-b-h (type 0) header */
hbh0->protocol = ip0->protocol;
ip0->protocol = 0;
ip0->payload_length = clib_host_to_net_u16 (new_l0);
/* Populate the (first) h-b-h list elt */
- next0 = IP_LOOKUP_NEXT_HOP_BY_HOP;
+ next0 = IP6_HBYH_INPUT_NEXT_IP6_LOOKUP;
if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
&& (b0->flags & VLIB_BUFFER_IS_TRACED)))
.error_strings = ip6_add_hop_by_hop_error_strings,
/* See ip/lookup.h */
- .n_next_nodes = IP_LOOKUP_N_NEXT,
+ .n_next_nodes = IP6_HBYH_INPUT_N_NEXT,
.next_nodes = {
- [IP_LOOKUP_NEXT_MISS] = "ip6-miss",
- [IP_LOOKUP_NEXT_DROP] = "ip6-drop",
- [IP_LOOKUP_NEXT_PUNT] = "ip6-punt",
- [IP_LOOKUP_NEXT_LOCAL] = "ip6-local",
- [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor",
- [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite",
- [IP_LOOKUP_NEXT_CLASSIFY] = "ip6-classify",
- [IP_LOOKUP_NEXT_MAP] = "ip6-map",
- [IP_LOOKUP_NEXT_MAP_T] = "ip6-map-t",
- [IP_LOOKUP_NEXT_SIXRD] = "ip6-sixrd",
- /* Next 3 arcs probably never used */
- [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop",
- [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop",
- [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop",
+#define _(s,n) [IP6_HBYH_INPUT_NEXT_##s] = n,
+ foreach_ip6_hbyh_input_next
+#undef _
},
};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_add_hop_by_hop_node, ip6_add_hop_by_hop_node_fn)
/* The main h-b-h tracer was already invoked, no need to do much here */
typedef struct {
#define foreach_ip6_pop_hop_by_hop_error \
_(PROCESSED, "Pkts w/ removed ip6 hop-by-hop options") \
-_(NO_HOHO, "Pkts w/ no ip6 hop-by-hop options")
+_(NO_HOHO, "Pkts w/ no ip6 hop-by-hop options") \
+_(SCV_PASSED, "Pkts with SCV in Policy") \
+_(SCV_FAILED, "Pkts with SCV out of Policy")
typedef enum {
#define _(sym,str) IP6_POP_HOP_BY_HOP_ERROR_##sym,
#undef _
};
+static inline void ioam_end_of_path_validation (vlib_main_t * vm,
+ ip6_header_t *ip0,
+ ip6_hop_by_hop_header_t *hbh0)
+{
+ ip6_hop_by_hop_option_t *opt0, *limit0;
+ ioam_pow_option_t * pow0;
+ u8 type0;
+ u64 final_cumulative = 0;
+ u64 random = 0;
+ u8 result = 0;
+
+ if (!hbh0 || !ip0) return;
+
+ opt0 = (ip6_hop_by_hop_option_t *)(hbh0+1);
+ limit0 = (ip6_hop_by_hop_option_t *)
+ ((u8 *)hbh0 + ((hbh0->length+1)<<3));
+
+ /* Scan the set of h-b-h options, process ones that we understand */
+ while (opt0 < limit0)
+ {
+ type0 = opt0->type & HBH_OPTION_TYPE_MASK;
+ switch (type0)
+ {
+ case HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE:
+ case HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST:
+ opt0 = (ip6_hop_by_hop_option_t *)
+ (((u8 *)opt0) + opt0->length
+ + sizeof (ip6_hop_by_hop_option_t));
+ break;
+ case HBH_OPTION_TYPE_IOAM_PROOF_OF_WORK:
+ pow0 = (ioam_pow_option_t *) opt0;
+ random = clib_net_to_host_u64(pow0->random);
+ final_cumulative = clib_net_to_host_u64(pow0->cumulative);
+ result = scv_validate (pow_profile,
+ final_cumulative, random);
+
+ if (result == 1)
+ {
+ vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index,
+ IP6_POP_HOP_BY_HOP_ERROR_SCV_PASSED, result);
+ }
+ else
+ {
+ vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index,
+ IP6_POP_HOP_BY_HOP_ERROR_SCV_FAILED, 1);
+ }
+ /* TODO: notify the scv failure*/
+ opt0 = (ip6_hop_by_hop_option_t *)
+ (((u8 *)opt0) + sizeof (ioam_pow_option_t));
+ break;
+
+ case 0: /* Pad */
+ opt0 = (ip6_hop_by_hop_option_t *) ((u8 *)opt0) + 1;
+ break;
+
+ default:
+ format(0, "Something is wrong\n");
+ break;
+ }
+ }
+}
+
+
static uword
ip6_pop_hop_by_hop_node_fn (vlib_main_t * vm,
vlib_node_runtime_t * node,
{
hbh0 = (ip6_hop_by_hop_header_t *)(ip0+1);
+ if (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP)
+ { /* First pass. Send to hbyh node. */
+ next0 = IP6_HBYH_INPUT_NEXT_IP6_LOOKUP;
+ goto out1;
+ }
+
+ /* Second pass */
/* Collect data from trace via callback */
next0 = ioam_end_of_path_cb ?
- ioam_end_of_path_cb (vm, node, b0, ip0, adj0)
- : adj0->saved_lookup_next_index;
-
-
+ ioam_end_of_path_cb (vm, node, b0, ip0, adj0) :
+ IP6_HBYH_INPUT_NEXT_IP6_REWRITE;
+ /* TODO:Temporarily doing it here.. do this validation in end_of_path_cb */
+ ioam_end_of_path_validation(vm, ip0, hbh0);
/* Pop the trace data */
vlib_buffer_advance (b0, (hbh0->length+1)<<3);
new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
}
else
{
- next0 = adj0->saved_lookup_next_index;
+ next0 = IP6_HBYH_INPUT_NEXT_IP6_LOOKUP;
no_header++;
}
t->next_index = next0;
}
+out1:
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
.error_strings = ip6_pop_hop_by_hop_error_strings,
/* See ip/lookup.h */
- .n_next_nodes = IP_LOOKUP_N_NEXT,
+ .n_next_nodes = IP6_HBYH_INPUT_N_NEXT,
.next_nodes = {
- [IP_LOOKUP_NEXT_MISS] = "ip6-miss",
- [IP_LOOKUP_NEXT_DROP] = "ip6-drop",
- [IP_LOOKUP_NEXT_PUNT] = "ip6-punt",
- [IP_LOOKUP_NEXT_LOCAL] = "ip6-local",
- [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor",
- [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite",
- [IP_LOOKUP_NEXT_CLASSIFY] = "ip6-classify",
- [IP_LOOKUP_NEXT_MAP] = "ip6-map",
- [IP_LOOKUP_NEXT_MAP_T] = "ip6-map-t",
- [IP_LOOKUP_NEXT_SIXRD] = "ip6-sixrd",
- /* Next 3 arcs probably never used */
- [IP_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop",
- [IP_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop",
- [IP_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop",
+#define _(s,n) [IP6_HBYH_INPUT_NEXT_##s] = n,
+ foreach_ip6_hbyh_input_next
+#undef _
},
};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_pop_hop_by_hop_node,
+ ip6_pop_hop_by_hop_node_fn)
static clib_error_t *
ip6_hop_by_hop_init (vlib_main_t * vm)
}
clib_error_t *
-clear_ioam_rewrite_fn()
+clear_ioam_rewrite_fn(void)
{
ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
return 0;
}
+
+clib_error_t * clear_ioam_rewrite_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ return(clear_ioam_rewrite_fn());
+}
VLIB_CLI_COMMAND (ip6_clear_ioam_trace_cmd, static) = {
.path = "clear ioam rewrite",
.short_help = "clear ioam rewrite",
- .function = clear_ioam_rewrite_fn,
+ .function = clear_ioam_rewrite_command_fn,
};
clib_error_t *
break;
default:
- return clib_error_return (0, "ip6_ioam_set_rewrite returned %d", rv);
+ return clib_error_return_code(0, rv, 0, "ip6_ioam_set_rewrite returned %d", rv);
}
return 0;
.function = ip6_set_ioam_destination_command_fn,
};
+
void vnet_register_ioam_end_of_path_callback (void *cb)
{
ip6_hop_by_hop_main_t * hm = &ip6_hop_by_hop_main;
hm->ioam_end_of_path_cb = cb;
}
+