2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 #include <vlib/vlib.h>
16 #include <vnet/vnet.h>
17 #include <vnet/pg/pg.h>
18 #include <vppinfra/error.h>
19 #include <vnet/ip/ip6.h>
21 #include <vppinfra/hash.h>
22 #include <vppinfra/error.h>
23 #include <vppinfra/elog.h>
25 #include <ioam/encap/ip6_ioam_pot.h>
26 #include <ioam/lib-pot/pot_util.h>
28 #define foreach_ip6_hop_by_hop_ioam_pot_stats \
29 _(PROCESSED, "Pkts with ip6 hop-by-hop pot options") \
30 _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \
31 _(PASSED, "Pkts with POT in Policy") \
32 _(FAILED, "Pkts with POT out of Policy")
34 static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = {
35 #define _(sym,string) string,
36 foreach_ip6_hop_by_hop_ioam_pot_stats
41 #define _(sym,str) IP6_IOAM_POT_##sym,
42 foreach_ip6_hop_by_hop_ioam_pot_stats
45 } ip6_ioam_pot_stats_t;
49 u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)];
52 vlib_main_t * vlib_main;
53 vnet_main_t * vnet_main;
54 } ip6_hop_by_hop_ioam_pot_main_t;
56 ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main;
59 ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment)
61 ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
63 hm->counters[counter_index] += increment;
67 static u8 * format_ioam_pot (u8 * s, va_list * args)
69 ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *);
70 u64 random, cumulative;
71 random = cumulative = 0;
74 random = clib_net_to_host_u64 (pot0->random);
75 cumulative = clib_net_to_host_u64 (pot0->cumulative);
78 s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x",
79 random, cumulative, pot0 ? pot0->reserved_profile_id : ~0);
84 ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt)
86 ioam_pot_option_t *pot;
88 s = format (s, " POT opt present\n");
89 pot = (ioam_pot_option_t *) opt;
90 s = format (s, " %U\n", format_ioam_pot, pot);
95 ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b,
97 ip6_hop_by_hop_option_t *opt0)
99 ioam_pot_option_t * pot0;
100 u64 random = 0, cumulative = 0;
102 u8 pot_profile_index;
103 pot_profile *pot_profile = 0, *new_profile = 0;
106 pot0 = (ioam_pot_option_t *) opt0;
107 pot_encap = (pot0->random == 0);
108 pot_profile_index = pot_profile_get_active_id();
109 pot_profile = pot_profile_get_active();
110 if (pot_encap && PREDICT_FALSE(!pot_profile))
112 ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
117 pot0->reserved_profile_id =
118 pot_profile_index & PROFILE_ID_MASK;
119 pot_profile_incr_usage_stats(pot_profile);
122 { /* Non encap node */
123 if (PREDICT_FALSE(pot0->reserved_profile_id !=
124 pot_profile_index || pot_profile == 0))
126 /* New profile announced by encap node. */
128 pot_profile_find(pot0->reserved_profile_id);
129 if (PREDICT_FALSE(new_profile == 0 ||
130 new_profile->valid == 0))
132 ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
137 pot_profile_index = pot0->reserved_profile_id;
138 pot_profile = new_profile;
139 pot_profile_set_active(pot_profile_index);
140 pot_profile_reset_usage_stats(pot_profile);
143 pot_profile_incr_usage_stats(pot_profile);
146 if (pot0->random == 0)
148 pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile));
149 pot0->cumulative = 0;
151 random = clib_net_to_host_u64(pot0->random);
152 cumulative = clib_net_to_host_u64(pot0->cumulative);
153 pot0->cumulative = clib_host_to_net_u64(
154 pot_update_cumulative(pot_profile,
157 ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1);
163 ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip,
164 ip6_hop_by_hop_option_t *opt0)
166 ioam_pot_option_t * pot0;
170 pot_profile *pot_profile = 0;
173 pot0 = (ioam_pot_option_t *) opt0;
174 random = clib_net_to_host_u64(pot0->random);
175 cumulative = clib_net_to_host_u64(pot0->cumulative);
176 pot_profile = pot_profile_get_active();
177 result = pot_validate (pot_profile,
182 ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1);
186 ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1);
191 int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 *rewrite_size)
193 ioam_pot_option_t * pot_option;
194 if (rewrite_string && *rewrite_size == sizeof(ioam_pot_option_t))
196 pot_option = (ioam_pot_option_t *)rewrite_string;
197 pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
198 | HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
199 pot_option->hdr.length = sizeof (ioam_pot_option_t) -
200 sizeof (ip6_hop_by_hop_option_t);
206 static clib_error_t *
207 ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm,
208 unformat_input_t * input,
209 vlib_cli_command_t * cmd)
211 ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
215 for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++)
217 s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i],
221 vlib_cli_output(vm, "%v", s);
227 VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = {
228 .path = "show ioam pot",
229 .short_help = "iOAM pot statistics",
230 .function = ip6_show_ioam_pot_cmd_fn,
234 static clib_error_t *
235 ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm)
237 ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main;
240 hm->vnet_main = vnet_get_main();
241 clib_memset(hm->counters, 0, sizeof(hm->counters));
243 if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler,
244 ip6_hbh_ioam_proof_of_transit_trace_handler) < 0)
245 return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed"));
247 if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
248 sizeof(ioam_pot_option_t),
249 ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0)
250 return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed"));
252 if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
253 ip6_hbh_ioam_proof_of_transit_pop_handler) < 0)
254 return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed"));
260 VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init) =
262 .runs_after = VLIB_INITS("ip6_hop_by_hop_ioam_init"),