/* * 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_hop_by_hop_ioam_h__ #define __included_ip6_hop_by_hop_ioam_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 { u8 next_index_by_protocol[256]; } ip6_local_hop_by_hop_runtime_t; typedef struct { /* The current rewrite we're using */ u8 *rewrite; /* Trace data processing callback */ void *ioam_end_of_path_cb; /* Configuration data */ /* Adjacency */ ip6_address_t adj; #define IOAM_HBYH_ADD 0 #define IOAM_HBYH_MOD 1 #define IOAM_HBYH_POP 2 u8 ioam_flag; /* time scale transform. Joy. */ u32 unix_time_0; f64 vlib_time_0; /* Trace option */ u8 has_trace_option; /* Pot option */ u8 has_pot_option; /* Per Packet Counter option */ u8 has_seqno_option; /* Enabling analyis of iOAM data on decap node */ u8 has_analyse_option; /* Array of function pointers to ADD and POP HBH option handling routines */ 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; ip6_local_hop_by_hop_runtime_t *ip6_local_hbh_runtime; /* convenience */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; } ip6_hop_by_hop_ioam_main_t; extern ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main; extern clib_error_t *ip6_ioam_enable (int has_trace_option, int has_pot_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); extern clib_error_t *clear_ioam_rewrite_fn (void); static inline u8 is_zero_ip4_address (ip4_address_t * a) { return (a->as_u32 == 0); } static inline void copy_ip6_address (ip6_address_t * dst, ip6_address_t * src) { dst->as_u64[0] = src->as_u64[0]; dst->as_u64[1] = src->as_u64[1]; } static inline void set_zero_ip6_address (ip6_address_t * a) { a->as_u64[0] = 0; a->as_u64[1] = 0; } static inline u8 cmp_ip6_address (ip6_address_t * a1, ip6_address_t * a2) { return ((a1->as_u64[0] == a2->as_u64[0]) && (a1->as_u64[1] == a2->as_u64[1])); } static inline u8 is_zero_ip6_address (ip6_address_t * a) { return ((a->as_u64[0] == 0) && (a->as_u64[1] == 0)); } int ip6_hbh_add_register_option (u8 option, u8 size, int rewrite_options (u8 * rewrite_string, u8 * size)); int ip6_hbh_add_unregister_option (u8 option); int ip6_hbh_pop_register_option (u8 option, 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 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_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); } int ip6_trace_profile_setup (); static inline 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); clib_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); } always_inline ip6_hop_by_hop_option_t * ip6_hbh_get_option (ip6_hop_by_hop_header_t * hbh0, u8 option_to_search) { ip6_hop_by_hop_option_t *opt0, *limit0; u8 type0; if (!hbh0) return NULL; 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; switch (type0) { case 0: /* Pad1 */ opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1; continue; case 1: /* PadN */ break; default: if (type0 == option_to_search) return opt0; break; } opt0 = (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length + sizeof (ip6_hop_by_hop_option_t)); } return NULL; } #endif /* __included_ip6_hop_by_hop_ioam_h__ */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */