diff options
author | AkshayaNadahalli <anadahal@cisco.com> | 2016-08-09 13:38:04 +0530 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2016-11-03 11:44:21 +0000 |
commit | ed4a2fdd4d62c46a2237157cd3a72bda16fceb6a (patch) | |
tree | 1fa59d681435a39f3b7f840b60229f8c3edf4f19 | |
parent | 273c26a531bf031b3426588041bad67fe7f0a246 (diff) |
Adding Sequence Number - Per Packet Counter(PPC) support for iOAM6.
- Added support in classifier session to identify a flow to be iOAM6 encap/decap
- Sequence number as part of iOAM6 E2E header is created as a plugin.
Change-Id: Ib7605de45aecff25d684d099b525f8dc96ee7038
Signed-off-by: AkshayaNadahalli <anadahal@cisco.com>
-rw-r--r-- | plugins/ioam-plugin/Makefile.am | 13 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c | 232 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h | 47 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c | 8 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c | 109 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h | 70 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c | 141 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c | 3 | ||||
-rw-r--r-- | plugins/ioam-plugin/ioam/lib-trace/trace_util.c | 5 | ||||
-rw-r--r-- | vnet/vnet/buffer.h | 2 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6.h | 4 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6_forward.c | 12 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6_hop_by_hop.c | 279 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6_hop_by_hop.h | 102 | ||||
-rw-r--r-- | vpp-api-test/vat/api_format.c | 24 | ||||
-rw-r--r-- | vpp/vpp-api/api.c | 3 | ||||
-rw-r--r-- | vpp/vpp-api/custom_dump.c | 40 | ||||
-rw-r--r-- | vpp/vpp-api/vpe.api | 8 |
18 files changed, 1006 insertions, 96 deletions
diff --git a/plugins/ioam-plugin/Makefile.am b/plugins/ioam-plugin/Makefile.am index 853ac6d37d1..3f1edb10910 100644 --- a/plugins/ioam-plugin/Makefile.am +++ b/plugins/ioam-plugin/Makefile.am @@ -115,7 +115,20 @@ ioam_trace_test_plugin_la_SOURCES = \ vppapitestplugins_LTLIBRARIES += ioam_trace_test_plugin.la vppplugins_LTLIBRARIES += ioam_trace_plugin.la +######################################## +# iOAM E2E plugin +######################################## + +ioam_e2e_plugin_la_SOURCES = \ + ioam/encap/ip6_ioam_e2e.c \ + ioam/encap/ip6_ioam_seqno.c \ + ioam/encap/ip6_ioam_seqno_analyse.c + +noinst_HEADERS += \ + ioam/encap/ip6_ioam_e2e.h \ + ioam/encap/ip6_ioam_seqno.h +vppplugins_LTLIBRARIES += ioam_e2e_plugin.la # Remove *.la files install-data-hook: diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c new file mode 100644 index 00000000000..0839cdceca7 --- /dev/null +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2016 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 <vlib/vlib.h> +#include <vnet/vnet.h> +#include <vnet/pg/pg.h> +#include <vppinfra/error.h> + +#include <vnet/ip/ip.h> + +#include <vppinfra/hash.h> +#include <vppinfra/error.h> +#include <vppinfra/elog.h> + +#include <vnet/ip/ip6_hop_by_hop.h> +#include <vnet/plugin/plugin.h> + +#include "ip6_ioam_e2e.h" + +ioam_e2e_main_t ioam_e2e_main; + +static u8 * ioam_e2e_trace_handler (u8 * s, + ip6_hop_by_hop_option_t *opt) +{ + ioam_e2e_option_t * e2e = (ioam_e2e_option_t *)opt; + u32 seqno = 0; + + if (e2e) + { + seqno = clib_net_to_host_u32 (e2e->e2e_data); + } + + s = format (s, "SeqNo = 0x%Lx", seqno); + return s; +} + +int +ioam_e2e_config_handler (void *data, u8 disable) +{ + int *analyse = data; + + /* Register hanlders if enabled */ + if (!disable) + { + /* If encap node register for encap handler */ + if (0 == *analyse) + { + if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_seqno_encap_handler, + ioam_e2e_trace_handler) < 0) + { + return (-1); + } + } + /* If analyze node then register for decap handler */ + else + { + if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_seqno_decap_handler) < 0) + { + return (-1); + } + } + return 0; + } + + /* UnRegister handlers */ + (void) ip6_hbh_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + (void) ip6_hbh_pop_unregister_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + return 0; +} + +int +ioam_e2e_rewrite_handler (u8 *rewrite_string, + u8 *rewrite_size) +{ + ioam_e2e_option_t *e2e_option; + + if (rewrite_string && *rewrite_size == sizeof(ioam_e2e_option_t)) + { + e2e_option = (ioam_e2e_option_t *)rewrite_string; + e2e_option->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE + | HBH_OPTION_TYPE_SKIP_UNKNOWN; + e2e_option->hdr.length = sizeof (ioam_e2e_option_t) - + sizeof (ip6_hop_by_hop_option_t); + return(0); + } + return(-1); +} + +u32 +ioam_e2e_flow_handler (u32 ctx, u8 add) +{ + ioam_e2e_data_t *data; + u16 i; + + if (add) + { + pool_get(ioam_e2e_main.e2e_data, data); + data->flow_ctx = ctx; + ioam_seqno_init_bitmap(&data->seqno_data); + return ((u32) (data - ioam_e2e_main.e2e_data)); + } + + /* Delete case */ + for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) + { + if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) + continue; + + data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); + if (data && (data->flow_ctx == ctx)) + { + pool_put_index(ioam_e2e_main.e2e_data, i); + return (0); + } + } + return 0; +} + +static clib_error_t * +ioam_show_e2e_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + ioam_e2e_data_t *e2e_data; + u8 *s = 0; + int i; + + vec_reset_length(s); + + s = format(0, "IOAM E2E information: \n"); + for (i = 0; i < vec_len(ioam_e2e_main.e2e_data); i++) + { + if (pool_is_free_index(ioam_e2e_main.e2e_data, i)) + continue; + + e2e_data = pool_elt_at_index(ioam_e2e_main.e2e_data, i); + s = format(s, "Flow name: %s\n", get_flow_name_from_flow_ctx(e2e_data->flow_ctx)); + + s = show_ioam_seqno_cmd_fn(s, + &e2e_data->seqno_data, + !IOAM_DEAP_ENABLED(e2e_data->flow_ctx)); + } + + vlib_cli_output(vm, "%v", s); + return 0; +} + + +VLIB_CLI_COMMAND (ioam_show_e2e_cmd, static) = { + .path = "show ioam e2e ", + .short_help = "show ioam e2e information", + .function = ioam_show_e2e_cmd_fn, +}; + +/* + * This routine exists to convince the vlib plugin framework that + * we haven't accidentally copied a random .dll into the plugin directory. + * + * Also collects global variable pointers passed from the vpp engine + */ +clib_error_t * +vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, + int from_early_init) +{ + clib_error_t * error = 0; + + ioam_e2e_main.vlib_main = vm; + ioam_e2e_main.vnet_main = h->vnet_main; + return error; +} + +/* + * Init handler E2E headet handling. + * Init hanlder registers encap, decap, trace and Rewrite handlers. + */ +static clib_error_t * +ioam_e2e_init (vlib_main_t * vm) +{ + clib_error_t * error; + + if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) + { + return(error); + } + + /* + * As of now we have only PPC under E2E header. + */ + if (ip6_hbh_config_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_e2e_config_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); + } + + if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + sizeof(ioam_e2e_option_t), + ioam_e2e_rewrite_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE for rewrite failed")); + } + + if (ip6_hbh_flow_handler_register(HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE, + ioam_e2e_flow_handler) < 0) + { + return (clib_error_create("Registration of " + "HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE Flow handler failed")); + } + + return (0); +} + +/* + * Init function for the E2E lib. + * ip6_hop_by_hop_ioam_e2e_init gets called during init. + */ +VLIB_INIT_FUNCTION (ioam_e2e_init); diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h new file mode 100644 index 00000000000..18f35f80c60 --- /dev/null +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_e2e.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 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_ip6_ioam_e2e_h__ +#define __included_ip6_ioam_e2e_h__ + +#include "ip6_ioam_seqno.h" + +typedef struct ioam_e2e_data_t_ { + u32 flow_ctx; + u32 pad; + ioam_seqno_data seqno_data; +} ioam_e2e_data_t; + +typedef struct { + ioam_e2e_data_t *e2e_data; + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} ioam_e2e_main_t; + +extern ioam_e2e_main_t ioam_e2e_main; + +static inline ioam_seqno_data * +ioam_e2ec_get_seqno_data_from_flow_ctx (u32 flow_ctx) +{ + ioam_e2e_data_t *data = NULL; + u32 index; + + index = get_flow_data_from_flow_ctx(flow_ctx, + HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE); + data = &ioam_e2e_main.e2e_data[index]; + return &(data->seqno_data); +} + +#endif /* __included_ioam_e2e_h__ */ diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c index 9daea9c058f..05f42c91d0f 100644 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_pot.c @@ -171,7 +171,7 @@ ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b, } int -ip6_hbh_ioam_proof_of_transit_pop_handler (ip6_header_t *ip, +ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt0) { ioam_pot_option_t * pot0; @@ -248,12 +248,6 @@ ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm) ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main; clib_error_t * error; - if ((error = vlib_call_init_function (vm, ip_main_init))) - return(error); - - if ((error = vlib_call_init_function (vm, ip6_lookup_init))) - return error; - if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init))) return(error); diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c new file mode 100644 index 00000000000..0b4d4192975 --- /dev/null +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 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 <vlib/vlib.h> +#include <vnet/vnet.h> +#include <vnet/pg/pg.h> +#include <vppinfra/error.h> + +#include <vnet/ip/ip.h> + +#include <vppinfra/hash.h> +#include <vppinfra/error.h> +#include <vppinfra/elog.h> + +#include "ip6_ioam_seqno.h" +#include "ip6_ioam_e2e.h" + +ioam_seqno_data_main_t ioam_seqno_main; + +void ioam_seqno_init_bitmap (ioam_seqno_data *data) +{ + seqno_bitmap *bitmap = &data->seqno_rx.bitmap; + bitmap->window_size = SEQNO_WINDOW_SIZE; + bitmap->array_size = SEQNO_WINDOW_ARRAY_SIZE; + bitmap->mask = 32 * SEQNO_WINDOW_ARRAY_SIZE - 1; + bitmap->array[0] = 0x00000000;/* pretend we haven seen sequence numbers 0*/ + bitmap->highest = 0; + + data->seq_num = 0; + return ; +} + +/* + * This Routine gets called from IPv6 hop-by-hop option handling. + * Only if we are encap node, then add PPC data. + * On a Transit(MID) node we dont do anything with E2E headers. + * On decap node decap is handled by seperate function. + */ +int +ioam_seqno_encap_handler (vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt) +{ + u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; + ioam_e2e_option_t * e2e; + int rv = 0; + ioam_seqno_data *data; + + data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); + e2e = (ioam_e2e_option_t *) opt; + e2e->e2e_data = clib_host_to_net_u32(++data->seq_num); + + return (rv); +} + +/* + * This Routine gets called on POP/Decap node. + */ +int +ioam_seqno_decap_handler (vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt) +{ + u32 opaque_index = vnet_buffer(b)->l2_classify.opaque_index; + ioam_e2e_option_t * e2e; + int rv = 0; + ioam_seqno_data *data; + + data = ioam_e2ec_get_seqno_data_from_flow_ctx(opaque_index); + e2e = (ioam_e2e_option_t *) opt; + ioam_analyze_seqno(&data->seqno_rx, (u64) clib_net_to_host_u32(e2e->e2e_data)); + + return (rv); +} + +u8 * +show_ioam_seqno_cmd_fn (u8 *s, ioam_seqno_data *seqno_data, u8 enc) +{ + seqno_rx_info *rx; + + s = format(s, "SeqNo Data:\n"); + if (enc) + { + s = format(s, " Current Seq. Number : %llu\n", seqno_data->seq_num); + } + else + { + rx = &seqno_data->seqno_rx; + s = format(s, " Highest Seq. Number : %llu\n", rx->bitmap.highest); + s = format(s, " Packets received : %llu\n", rx->rx_packets); + s = format(s, " Lost packets : %llu\n", rx->lost_packets); + s = format(s, " Reordered packets : %llu\n", rx->reordered_packets); + s = format(s, " Duplicate packets : %llu\n", rx->dup_packets); + } + + format(s, "\n"); + return s; +} diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h new file mode 100644 index 00000000000..13a84db0d71 --- /dev/null +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 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_ip6_ioam_seqno_h__ +#define __included_ip6_ioam_seqno_h__ + +#include <vnet/ip/ip6_packet.h> +#include <vnet/ip/ip6_hop_by_hop.h> + +#define SEQ_CHECK_VALUE 0x80000000 /* for seq number wraparound detection */ + +#define SEQNO_WINDOW_SIZE 2048 +#define SEQNO_WINDOW_ARRAY_SIZE 64 + +typedef struct seqno_bitmap_ { + u32 window_size; + u32 array_size; + u32 mask; + u32 pad; + u64 highest; + u64 array[SEQNO_WINDOW_ARRAY_SIZE]; /* Will be alloc to array_size */ +} seqno_bitmap; + +typedef struct seqno_rx_info_ { + u64 rx_packets; + u64 lost_packets; + u64 reordered_packets; + u64 dup_packets; + seqno_bitmap bitmap; +} seqno_rx_info; + +/* This structure is 64-byte aligned */ +typedef struct ioam_seqno_data_ { + union { + u32 seq_num; /* Useful only for encap node */ + seqno_rx_info seqno_rx; + }; +} ioam_seqno_data; + +typedef struct ioam_seqno_data_main_t_ { + ioam_seqno_data *seqno_data; +} ioam_seqno_data_main_t; + +void ioam_seqno_init_bitmap(ioam_seqno_data *data); + +int ioam_seqno_encap_handler(vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt); + +int +ioam_seqno_decap_handler(vlib_buffer_t *b, ip6_header_t *ip, + ip6_hop_by_hop_option_t *opt); + +void ioam_analyze_seqno(seqno_rx_info *ppc_rx, u64 seqno); + +u8 * +show_ioam_seqno_cmd_fn(u8 *s, ioam_seqno_data *seqno_data, u8 enc); + +#endif diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c new file mode 100644 index 00000000000..4638871c224 --- /dev/null +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_seqno_analyse.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vnet/vnet.h> +#include "ip6_ioam_seqno.h" + +static inline void BIT_SET (u64 *p, u32 n) +{ + p[ n>>5 ] |= (1 << (n&31)); +} + +static inline int BIT_TEST (u64 *p, u32 n) +{ + return p[ n>>5 ] & (1 << (n&31)); +} + +static void BIT_CLEAR (u64 *p, u64 start, int num_bits, u32 mask) +{ + int n, t; + int start_index = (start >> 5); + int mask_index = (mask >> 5); + + start_index &= mask_index; + if (start & 0x1f) + { + int start_bit = (start & 0x1f); + + n = (1 << start_bit)-1; + t = start_bit + num_bits; + if (t < 32) + { + n |= ~((1 << t)-1); + p[ start_index ] &= n; + return; + } + p[ start_index ] &= n; + start_index = (start_index + 1) & mask_index; + num_bits -= (32 - start_bit); + } + while (num_bits >= 32) + { + p[ start_index ] = 0; + start_index = (start_index + 1) & mask_index; + num_bits -= 32; + } + n = ~((1 << num_bits) - 1); + p[ start_index ] &= n; +} + +static inline u8 seqno_check_wraparound(u32 a, u32 b) +{ + if ((a != b) && (a > b) && ((a - b) > SEQ_CHECK_VALUE)) + { + return 1; + } + return 0; +} + +/* + * Function to analyze the PPC value recevied. + * - Updates the bitmap with received sequence number + * - counts the received/lost/duplicate/reordered packets + */ +void ioam_analyze_seqno (seqno_rx_info *seqno_rx, u64 seqno) +{ + int diff; + static int peer_dead_count; + seqno_bitmap *bitmap = &seqno_rx->bitmap; + + seqno_rx->rx_packets++; + + if (seqno > bitmap->highest) + { /* new larger sequence number */ + peer_dead_count = 0; + diff = seqno - bitmap->highest; + if (diff < bitmap->window_size) + { + if (diff > 1) + { /* diff==1 is *such* a common case it's a win to optimize it */ + BIT_CLEAR(bitmap->array, bitmap->highest+1, diff-1, bitmap->mask); + seqno_rx->lost_packets += diff -1; + } + } + else + { + seqno_rx->lost_packets += diff -1; + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); + } + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + return; + } + + /* we've seen a bigger seq number before */ + diff = bitmap->highest - seqno; + if (diff >= bitmap->window_size) + { + if (seqno_check_wraparound(bitmap->highest, seqno)) + { + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64)); + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + return; + } + else + { + peer_dead_count++; + if (peer_dead_count > 25) + { + peer_dead_count = 0; + memset( bitmap->array, 0, bitmap->array_size * sizeof(u64) ); + BIT_SET(bitmap->array, seqno & bitmap->mask); + bitmap->highest = seqno; + } + //ppc_rx->reordered_packets++; + } + return; + } + + if (BIT_TEST(bitmap->array, seqno & bitmap->mask)) + { + seqno_rx->dup_packets++; + return; /* Already seen */ + } + seqno_rx->reordered_packets++; + seqno_rx->lost_packets--; + BIT_SET(bitmap->array, seqno & bitmap->mask); + return; +} diff --git a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c b/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c index 5c9814051da..16e10817d00 100644 --- a/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c +++ b/plugins/ioam-plugin/ioam/encap/ip6_ioam_trace.c @@ -153,7 +153,8 @@ ioam_trace_get_sizeof_handler (u32 * result) if (PREDICT_FALSE (profile->num_elts * trace_data_size > 254)) return VNET_API_ERROR_INVALID_VALUE; - size += profile->num_elts * trace_data_size; + size += + sizeof (ioam_trace_option_t) + (profile->num_elts * trace_data_size); *result = size; return 0; diff --git a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c b/plugins/ioam-plugin/ioam/lib-trace/trace_util.c index ca9adcd1225..adc02b20f56 100644 --- a/plugins/ioam-plugin/ioam/lib-trace/trace_util.c +++ b/plugins/ioam-plugin/ioam/lib-trace/trace_util.c @@ -35,7 +35,7 @@ trace_profile_cleanup (trace_profile * profile) if (0 != (rv = ip6_ioam_set_rewrite (&hm->rewrite, hm->has_trace_option, - hm->has_pot_option, hm->has_ppc_option))) + hm->has_pot_option, hm->has_seqno_option))) return (-1); return 0; @@ -89,7 +89,8 @@ trace_profile_create (trace_profile * profile, u8 trace_type, u8 num_elts, if (0 != (rv = ip6_ioam_set_rewrite (&hm->rewrite, hm->has_trace_option, - hm->has_pot_option, hm->has_ppc_option))) + hm->has_pot_option, + hm->has_seqno_option))) return (-1); } diff --git a/vnet/vnet/buffer.h b/vnet/vnet/buffer.h index 6385f19142c..fafb318104e 100644 --- a/vnet/vnet/buffer.h +++ b/vnet/vnet/buffer.h @@ -182,8 +182,8 @@ typedef struct struct { u64 pad; - u32 opaque_index; u32 table_index; + u32 opaque_index; u64 hash; } l2_classify; diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h index f6008d71ea1..8b3b9973bf4 100644 --- a/vnet/vnet/ip/ip6.h +++ b/vnet/vnet/ip/ip6.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * Copyright (c) 2016 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: @@ -521,6 +521,6 @@ int ip6_hbh_unregister_option (u8 option); void ip6_hbh_set_next_override (uword next); /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */ -#define OI_DECAP 100 +#define OI_DECAP 0x80000000 #endif /* included_ip_ip6_h */ diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c index 4493cb4cff3..53d13db2be3 100644 --- a/vnet/vnet/ip/ip6_forward.c +++ b/vnet/vnet/ip/ip6_forward.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * Copyright (c) 2016 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: @@ -2459,12 +2459,12 @@ ip6_hop_by_hop (vlib_main_t * vm, outdual: /* Has the classifier flagged this buffer for special treatment? */ - if ((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP)) - next0 = hm->next_override; + if (PREDICT_FALSE((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index & OI_DECAP))) + next0 = hm->next_override; /* Has the classifier flagged this buffer for special treatment? */ - if ((error1 == 0) && (vnet_buffer(b1)->l2_classify.opaque_index == OI_DECAP)) - next1 = hm->next_override; + if (PREDICT_FALSE((error1 == 0) && (vnet_buffer(b1)->l2_classify.opaque_index & OI_DECAP))) + next1 = hm->next_override; if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE))) { @@ -2542,7 +2542,7 @@ ip6_hop_by_hop (vlib_main_t * vm, out0: /* Has the classifier flagged this buffer for special treatment? */ - if ((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index == OI_DECAP)) + if (PREDICT_FALSE((error0 == 0) && (vnet_buffer(b0)->l2_classify.opaque_index & OI_DECAP))) next0 = hm->next_override; if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { diff --git a/vnet/vnet/ip/ip6_hop_by_hop.c b/vnet/vnet/ip/ip6_hop_by_hop.c index 72490b915e4..e8bc8906335 100644 --- a/vnet/vnet/ip/ip6_hop_by_hop.c +++ b/vnet/vnet/ip/ip6_hop_by_hop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * Copyright (c) 2016 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: @@ -25,6 +25,7 @@ #include <vnet/ip/ip6_hop_by_hop.h> #include <vnet/fib/ip6_fib.h> +#include <vnet/classify/vnet_classify.h> /** * @file @@ -40,8 +41,6 @@ * in-band OAM can be enabled for IPv6 traffic. */ -char *ppc_state[] = { "None", "Encap", "Decap" }; - ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; #define foreach_ip6_hbyh_ioam_input_next \ @@ -58,6 +57,68 @@ typedef enum } ip6_hbyh_ioam_input_next_t; +u32 +ioam_flow_add (u8 encap, u8 * flow_name) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + flow_data_t *flow = 0; + u32 index = 0; + u8 i; + + pool_get (hm->flows, flow); + memset (flow, 0, sizeof (flow_data_t)); + + index = flow - hm->flows; + strncpy ((char *) flow->flow_name, (char *) flow_name, 31); + + if (!encap) + IOAM_SET_DECAP (index); + + for (i = 0; i < 255; i++) + { + if (hm->flow_handler[i]) + flow->ctx[i] = hm->flow_handler[i] (index, 1); + } + return (index); +} + +static uword +unformat_opaque_ioam (unformat_input_t * input, va_list * args) +{ + u64 *opaquep = va_arg (*args, u64 *); + u8 *flow_name = NULL; + uword ret = 0; + + if (unformat (input, "ioam-encap %s", &flow_name)) + { + *opaquep = ioam_flow_add (1, flow_name); + ret = 1; + } + else if (unformat (input, "ioam-decap %s", &flow_name)) + { + *opaquep = ioam_flow_add (0, flow_name); + ret = 1; + } + + vec_free (flow_name); + return ret; +} + +u8 * +get_flow_name_from_flow_ctx (u32 flow_ctx) +{ + flow_data_t *flow = NULL; + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + u32 index; + + index = IOAM_MASK_DECAP_BIT (flow_ctx); + + if (pool_is_free_index (hm->flows, index)) + return NULL; + + flow = pool_elt_at_index (hm->flows, index); + return (flow->flow_name); +} /* The main h-b-h tracer will be invoked, no need to do much here */ int @@ -96,6 +157,72 @@ ip6_hbh_add_unregister_option (u8 option) return (0); } +/* Config handler registration */ +int +ip6_hbh_config_handler_register (u8 option, + int config_handler (void *data, u8 disable)) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->config_handler)); + + /* Already registered */ + if (hm->config_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->config_handler[option] = config_handler; + + return (0); +} + +int +ip6_hbh_config_handler_unregister (u8 option) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->config_handler)); + + /* Not registered */ + if (!hm->config_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->config_handler[option] = NULL; + return (0); +} + +/* Flow handler registration */ +int +ip6_hbh_flow_handler_register (u8 option, + u32 ioam_flow_handler (u32 flow_ctx, u8 add)) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->flow_handler)); + + /* Already registered */ + if (hm->flow_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->flow_handler[option] = ioam_flow_handler; + + return (0); +} + +int +ip6_hbh_flow_handler_unregister (u8 option) +{ + ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + + ASSERT (option < ARRAY_LEN (hm->flow_handler)); + + /* Not registered */ + if (!hm->flow_handler[option]) + return (VNET_API_ERROR_INVALID_REGISTRATION); + + hm->flow_handler[option] = NULL; + return (0); +} + typedef struct { u32 next_index; @@ -374,7 +501,8 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip6_add_hop_by_hop_node, int ip6_hbh_pop_register_option (u8 option, - int options (ip6_header_t * ip, + int options (vlib_buffer_t * b, + ip6_header_t * ip, ip6_hop_by_hop_option_t * opt)) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; @@ -429,7 +557,8 @@ static char *ip6_pop_hop_by_hop_error_strings[] = { static inline void ioam_pop_hop_by_hop_processing (vlib_main_t * vm, ip6_header_t * ip0, - ip6_hop_by_hop_header_t * hbh0) + ip6_hop_by_hop_header_t * hbh0, + vlib_buffer_t * b) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; ip6_hop_by_hop_option_t *opt0, *limit0; @@ -456,7 +585,7 @@ ioam_pop_hop_by_hop_processing (vlib_main_t * vm, default: if (hm->pop_options[type0]) { - if ((*hm->pop_options[type0]) (ip0, opt0) < 0) + if ((*hm->pop_options[type0]) (b, ip0, opt0) < 0) { vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index, @@ -543,8 +672,8 @@ ip6_pop_hop_by_hop_node_fn (vlib_main_t * vm, hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1); hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1); - ioam_pop_hop_by_hop_processing (vm, ip0, hbh0); - ioam_pop_hop_by_hop_processing (vm, ip1, hbh1); + ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0); + ioam_pop_hop_by_hop_processing (vm, ip1, hbh1, b1); vlib_buffer_advance (b0, (hbh0->length + 1) << 3); vlib_buffer_advance (b1, (hbh1->length + 1) << 3); @@ -632,7 +761,7 @@ ip6_pop_hop_by_hop_node_fn (vlib_main_t * vm, hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1); /* TODO:Temporarily doing it here.. do this validation in end_of_path_cb */ - ioam_pop_hop_by_hop_processing (vm, ip0, hbh0); + ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0); /* Pop the trace data */ vlib_buffer_advance (b0, (hbh0->length + 1) << 3); new_l0 = clib_net_to_host_u16 (ip0->payload_length) - @@ -690,8 +819,15 @@ 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_ioam_init (vlib_main_t * vm) { + clib_error_t *error; ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; + if ((error = vlib_call_init_function (vm, ip_main_init))) + return (error); + + if ((error = vlib_call_init_function (vm, ip6_lookup_init))) + return error; + hm->vlib_main = vm; hm->vnet_main = vnet_get_main (); hm->unix_time_0 = (u32) time (0); /* Store starting time */ @@ -701,6 +837,8 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip6_pop_hop_by_hop_node, memset (hm->pop_options, 0, sizeof (hm->pop_options)); memset (hm->options_size, 0, sizeof (hm->options_size)); + vnet_classify_register_unformat_opaque_index_fn (unformat_opaque_ioam); + return (0); } @@ -708,15 +846,15 @@ VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_init); int ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, - int has_pot_option, int has_ppc_option) + int has_pot_option, int has_seqno_option) { ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; - u8 *rewrite = 0; + u8 *rewrite = NULL; u32 size, rnd_size; ip6_hop_by_hop_header_t *hbh; u8 *current; - u8 trace_data_size = 0; - u8 pot_data_size = 0; + u8 *trace_data_size = NULL; + u8 *pot_data_size = NULL; vec_free (*rwp); @@ -730,16 +868,19 @@ ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, if (has_trace_option && hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] != 0) { - size += sizeof (ip6_hop_by_hop_option_t); size += hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; } if (has_pot_option && hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) { - size += sizeof (ip6_hop_by_hop_option_t); size += hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; } + if (has_seqno_option) + { + size += hm->options_size[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]; + } + /* Round to a multiple of 8 octets */ rnd_size = (size + 7) & ~7; @@ -757,22 +898,32 @@ ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, if (0 != (hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST])) { trace_data_size = - hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; + &hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (current, - &trace_data_size)) - current += hm->options_size[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]; + trace_data_size)) + current += *trace_data_size; } } if (has_pot_option && hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0) { - pot_data_size = hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; + pot_data_size = + &hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]; if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (current, - &pot_data_size)) - current += - sizeof (hm->options_size[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]); + pot_data_size)) + current += *pot_data_size; + } + + if (has_seqno_option && + (hm->add_options[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] != 0)) + { + if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] (current, + & + (hm->options_size + [HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]))) + current += hm->options_size[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]; } *rwp = rewrite; @@ -788,7 +939,20 @@ clear_ioam_rewrite_fn (void) hm->rewrite = 0; hm->has_trace_option = 0; hm->has_pot_option = 0; - hm->has_ppc_option = 0; + hm->has_seqno_option = 0; + hm->has_analyse_option = 0; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (NULL, 1); + + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (NULL, 1); + + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]) + { + hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] ((void *) + &hm->has_analyse_option, + 1); + } return 0; } @@ -819,19 +983,43 @@ VLIB_CLI_COMMAND (ip6_clear_ioam_rewrite_cmd, static) = { /* *INDENT-ON* */ clib_error_t * -ip6_ioam_enable (int has_trace_option, int has_pot_option, int has_ppc_option) +ip6_ioam_enable (int has_trace_option, int has_pot_option, + int has_seqno_option, int has_analyse_option) { int rv; ip6_hop_by_hop_ioam_main_t *hm = &ip6_hop_by_hop_ioam_main; rv = ip6_ioam_set_rewrite (&hm->rewrite, has_trace_option, - has_pot_option, has_ppc_option); + has_pot_option, has_seqno_option); switch (rv) { case 0: - hm->has_trace_option = has_trace_option; - hm->has_pot_option = has_pot_option; - hm->has_ppc_option = has_ppc_option; + if (has_trace_option) + { + hm->has_trace_option = has_trace_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] (NULL, + 0); + } + + if (has_pot_option) + { + hm->has_pot_option = has_pot_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]) + hm->config_handler[HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] (NULL, + 0); + } + hm->has_analyse_option = has_analyse_option; + if (has_seqno_option) + { + hm->has_seqno_option = has_seqno_option; + if (hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE]) + { + hm->config_handler[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] ((void *) + &has_analyse_option, + 0); + } + } break; default: @@ -850,7 +1038,8 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, { int has_trace_option = 0; int has_pot_option = 0; - int has_ppc_option = 0; + int has_seqno_option = 0; + int has_analyse_option = 0; clib_error_t *rv = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -859,18 +1048,17 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, has_trace_option = 1; else if (unformat (input, "pot")) has_pot_option = 1; - else if (unformat (input, "ppc encap")) - has_ppc_option = PPC_ENCAP; - else if (unformat (input, "ppc decap")) - has_ppc_option = PPC_DECAP; - else if (unformat (input, "ppc none")) - has_ppc_option = PPC_NONE; + else if (unformat (input, "seqno")) + has_seqno_option = 1; + else if (unformat (input, "analyse")) + has_analyse_option = 1; else break; } - rv = ip6_ioam_enable (has_trace_option, has_pot_option, has_ppc_option); + rv = ip6_ioam_enable (has_trace_option, has_pot_option, + has_seqno_option, has_analyse_option); return rv; } @@ -896,7 +1084,7 @@ ip6_set_ioam_rewrite_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip6_set_ioam_rewrite_cmd, static) = { .path = "set ioam rewrite", - .short_help = "set ioam rewrite [trace] [pot] [ppc <encap|decap|none>]", + .short_help = "set ioam [trace] [pot] [seqno] [analyse]", .function = ip6_set_ioam_rewrite_command_fn, }; /* *INDENT-ON* */ @@ -945,14 +1133,15 @@ ip6_show_ioam_summary_cmd_fn (vlib_main_t * vm, format (s, "Try 'show ioam pot and show pot profile' for more information\n"); - s = format (s, " EDGE TO EDGE - PPC OPTION - %d (%s)\n", - hm->has_ppc_option, ppc_state[hm->has_ppc_option]); -#if 0 - /* 'show ioam ppc' command does not exist. Not sure if it was removed */ - /* or yet to be added. Comment out for now. */ - if (hm->has_ppc_option) - s = format (s, "Try 'show ioam ppc' for more information\n"); -#endif + s = format (s, " EDGE TO EDGE - SeqNo OPTION - %d (%s)\n", + hm->has_seqno_option, + hm->has_seqno_option ? "Enabled" : "Disabled"); + if (hm->has_seqno_option) + s = format (s, "Try 'show ioam e2e' for more information\n"); + + s = format (s, " iOAM Analyse OPTION - %d (%s)\n", + hm->has_analyse_option, + hm->has_analyse_option ? "Enabled" : "Disabled"); vlib_cli_output (vm, "%v", s); vec_free (s); diff --git a/vnet/vnet/ip/ip6_hop_by_hop.h b/vnet/vnet/ip/ip6_hop_by_hop.h index dae58619e24..7d157cf55e7 100644 --- a/vnet/vnet/ip/ip6_hop_by_hop.h +++ b/vnet/vnet/ip/ip6_hop_by_hop.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * Copyright (c) 2016 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: @@ -15,10 +15,30 @@ #ifndef __included_ip6_hop_by_hop_ioam_h__ #define __included_ip6_hop_by_hop_ioam_h__ -#include <vnet/ip/ip6_hop_by_hop.h> #include <vnet/ip/ip6_hop_by_hop_packet.h> #include <vnet/ip/ip.h> + +#define MAX_IP6_HBH_OPTION 256 + +/* To determine whether a node is decap MS bit is set */ +#define IOAM_DECAP_BIT 0x80000000 + +#define IOAM_DEAP_ENABLED(opaque_data) (opaque_data & IOAM_DECAP_BIT) + +#define IOAM_SET_DECAP(opaque_data) \ + (opaque_data |= IOAM_DECAP_BIT) + +#define IOAM_MASK_DECAP_BIT(x) (x & ~IOAM_DECAP_BIT) + +/* + * Stores the run time flow data of hbh options + */ +typedef struct { + u32 ctx[MAX_IP6_HBH_OPTION]; + u8 flow_name[64]; +} flow_data_t; + typedef struct { /* The current rewrite we're using */ u8 * rewrite; @@ -43,10 +63,11 @@ typedef struct { /* Pot option */ u8 has_pot_option; -#define PPC_NONE 0 -#define PPC_ENCAP 1 -#define PPC_DECAP 2 - u8 has_ppc_option; + /* Per Packet Counter option */ + u8 has_seqno_option; + + /* Enabling analyis of iOAM data on decap node */ + u8 has_analyse_option; #define TSP_SECONDS 0 #define TSP_MILLISECONDS 1 @@ -54,11 +75,16 @@ typedef struct { #define TSP_NANOSECONDS 3 /* Array of function pointers to ADD and POP HBH option handling routines */ - u8 options_size[256]; - int (*add_options[256])(u8 *rewrite_string, u8 *rewrite_size); - int (*pop_options[256])(ip6_header_t *ip, ip6_hop_by_hop_option_t *opt); - int (*get_sizeof_options[256])(u32 *rewrite_size); - + u8 options_size[MAX_IP6_HBH_OPTION]; + int (*add_options[MAX_IP6_HBH_OPTION])(u8 *rewrite_string, u8 *rewrite_size); + int (*pop_options[MAX_IP6_HBH_OPTION])(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt); + int (*get_sizeof_options[MAX_IP6_HBH_OPTION])(u32 *rewrite_size); + int (*config_handler[MAX_IP6_HBH_OPTION]) (void *data, u8 disable); + + /* Array of function pointers to handle hbh options being used with classifier */ + u32 (*flow_handler[MAX_IP6_HBH_OPTION])(u32 flow_ctx, u8 add); + flow_data_t *flows; + /* convenience */ vlib_main_t * vlib_main; vnet_main_t * vnet_main; @@ -67,9 +93,11 @@ typedef struct { extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; extern u8 * format_path_map(u8 * s, va_list * args); + extern clib_error_t * ip6_ioam_enable(int has_trace_option, int has_pot_option, - int has_e2e_option); + int has_seqno_option, int has_analyse_option); + extern int ip6_ioam_set_destination (ip6_address_t *addr, u32 mask_width, u32 vrf_id, int is_add, int is_pop, int is_none); @@ -107,7 +135,8 @@ int ip6_hbh_add_register_option (u8 option, int ip6_hbh_add_unregister_option (u8 option); int ip6_hbh_pop_register_option (u8 option, - int options(ip6_header_t *ip, ip6_hop_by_hop_option_t *opt)); + int options(vlib_buffer_t *b, + ip6_header_t *ip, ip6_hop_by_hop_option_t *opt)); int ip6_hbh_pop_unregister_option (u8 option); int @@ -115,6 +144,49 @@ ip6_hbh_get_sizeof_register_option (u8 option, int get_sizeof_hdr_options(u32 *rewrite_size)); int -ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option, - int has_pot_option, int has_ppc_option); +ip6_ioam_set_rewrite (u8 **rwp, int has_trace_option, + int has_pot_option, int has_seq_no); + +int +ip6_hbh_config_handler_register (u8 option, + int config_handler(void *data, u8 disable)); + +int ip6_hbh_config_handler_unregister (u8 option); + +int ip6_hbh_flow_handler_register(u8 option, + u32 ioam_flow_handler(u32 flow_ctx, u8 add)); + +int ip6_hbh_flow_handler_unregister(u8 option); + +u8 * get_flow_name_from_flow_ctx(u32 flow_ctx); + +static inline flow_data_t * get_flow (u32 index) +{ + flow_data_t *flow = NULL; + ip6_hop_by_hop_ioam_main_t * hm = &ip6_hop_by_hop_ioam_main; + + if (pool_is_free_index (hm->flows, index)) + return NULL; + + flow = pool_elt_at_index (hm->flows, index); + return flow; +} + +static inline u32 get_flow_data_from_flow_ctx (u32 flow_ctx, u8 option) +{ + flow_data_t *flow = NULL; + ip6_hop_by_hop_ioam_main_t * hm = &ip6_hop_by_hop_ioam_main; + u32 index; + + index = IOAM_MASK_DECAP_BIT(flow_ctx); + //flow = pool_elt_at_index (hm->flows, index); + flow = &hm->flows[index]; + return (flow->ctx[option]); +} + +static inline u8 is_seqno_enabled (void) +{ + return (ip6_hop_by_hop_ioam_main.has_seqno_option); +} + #endif /* __included_ip6_hop_by_hop_ioam_h__ */ diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index 6f11083844b..120c39c4dba 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -7814,28 +7814,28 @@ api_ioam_enable (vat_main_t * vam) f64 timeout; u32 id = 0; int has_trace_option = 0; - int has_pow_option = 0; - int has_ppc_option = 0; + int has_pot_option = 0; + int has_seqno_option = 0; + int has_analyse_option = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "trace")) has_trace_option = 1; - else if (unformat (input, "pow")) - has_pow_option = 1; - else if (unformat (input, "ppc encap")) - has_ppc_option = PPC_ENCAP; - else if (unformat (input, "ppc decap")) - has_ppc_option = PPC_DECAP; - else if (unformat (input, "ppc none")) - has_ppc_option = PPC_NONE; + else if (unformat (input, "pot")) + has_pot_option = 1; + else if (unformat (input, "seqno")) + has_seqno_option = 1; + else if (unformat (input, "analyse")) + has_analyse_option = 1; else break; } M (IOAM_ENABLE, ioam_enable); mp->id = htons (id); - mp->trace_ppc = has_ppc_option; - mp->pow_enable = has_pow_option; + mp->seqno = has_seqno_option; + mp->analyse = has_analyse_option; + mp->pot_enable = has_pot_option; mp->trace_enable = has_trace_option; S; diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index 81cd8c358ff..c1f826391ce 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -7233,7 +7233,8 @@ vl_api_ioam_enable_t_handler (vl_api_ioam_enable_t * mp) /* Ignoring the profile id as currently a single profile * is supported */ - error = ip6_ioam_enable (mp->trace_enable, mp->pow_enable, mp->trace_ppc); + error = ip6_ioam_enable (mp->trace_enable, mp->pot_enable, + mp->seqno, mp->analyse); if (error) { clib_error_report (error); diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c index 6406cbad3f3..45d7b96a203 100644 --- a/vpp/vpp-api/custom_dump.c +++ b/vpp/vpp-api/custom_dump.c @@ -2804,6 +2804,42 @@ static void *vl_api_get_first_msg_id_t_print FINISH; } +static void *vl_api_ioam_enable_t_print + (vl_api_ioam_enable_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: ioam_enable "); + + if (mp->trace_enable) + s = format (s, "trace enabled"); + + if (mp->pot_enable) + s = format (s, "POT enabled"); + + if (mp->seqno) + s = format (s, "Seqno enabled"); + + if (mp->analyse) + s = format (s, "Analyse enabled"); + + FINISH; +} + +static void *vl_api_ioam_disable_t_print + (vl_api_ioam_disable_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: ioam_disable "); + s = format (s, "trace disabled"); + s = format (s, "POT disabled"); + s = format (s, "Seqno disabled"); + s = format (s, "Analyse disabled"); + + FINISH; +} + #define foreach_custom_print_no_arg_function \ _(lisp_eid_table_vni_dump) \ _(lisp_map_resolver_dump) \ @@ -2968,7 +3004,9 @@ _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \ _(PUNT, punt) \ _(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \ _(FLOW_CLASSIFY_DUMP, flow_classify_dump) \ -_(GET_FIRST_MSG_ID, get_first_msg_id) +_(GET_FIRST_MSG_ID, get_first_msg_id) \ +_(IOAM_ENABLE, ioam_enable) \ +_(IOAM_DISABLE, ioam_disable) void vl_msg_api_custom_dump_configure (api_main_t * am) { diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index c5eacce5413..3ec41abc3b1 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -4124,7 +4124,8 @@ define sw_interface_clear_stats_reply /** \brief IOAM enable : Enable in-band OAM @param id - profile id - @param trace_ppc - Trace PPC (none/encap/decap) + @param seqno - To enable Seqno Processing + @param analyse - Enabling analysis of iOAM at decap node @param pow_enable - Proof of Work enabled or not flag @param trace_enable - iOAM Trace enabled or not flag */ @@ -4133,8 +4134,9 @@ define ioam_enable u32 client_index; u32 context; u16 id; - u8 trace_ppc; - u8 pow_enable; + u8 seqno; + u8 analyse; + u8 pot_enable; u8 trace_enable; u32 node_id; }; |