Line data Source code
1 : /*
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:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
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.
14 : */
15 : #include <vlib/vlib.h>
16 : #include <vnet/vnet.h>
17 : #include <vppinfra/error.h>
18 : #include <vnet/ip/ip6.h>
19 :
20 : #include <vppinfra/hash.h>
21 : #include <vppinfra/error.h>
22 : #include <vppinfra/elog.h>
23 :
24 : #include <ioam/encap/ip6_ioam_pot.h>
25 : #include <ioam/lib-pot/pot_util.h>
26 :
27 : #define foreach_ip6_hop_by_hop_ioam_pot_stats \
28 : _(PROCESSED, "Pkts with ip6 hop-by-hop pot options") \
29 : _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \
30 : _(PASSED, "Pkts with POT in Policy") \
31 : _(FAILED, "Pkts with POT out of Policy")
32 :
33 : static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = {
34 : #define _(sym,string) string,
35 : foreach_ip6_hop_by_hop_ioam_pot_stats
36 : #undef _
37 : };
38 :
39 : typedef enum {
40 : #define _(sym,str) IP6_IOAM_POT_##sym,
41 : foreach_ip6_hop_by_hop_ioam_pot_stats
42 : #undef _
43 : IP6_IOAM_POT_N_STATS,
44 : } ip6_ioam_pot_stats_t;
45 :
46 : typedef struct {
47 : /* stats */
48 : u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)];
49 :
50 : /* convenience */
51 : vlib_main_t * vlib_main;
52 : vnet_main_t * vnet_main;
53 : } ip6_hop_by_hop_ioam_pot_main_t;
54 :
55 : ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main;
56 :
57 : always_inline void
58 0 : ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment)
59 : {
60 0 : ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
61 :
62 0 : hm->counters[counter_index] += increment;
63 0 : }
64 :
65 :
66 0 : static u8 * format_ioam_pot (u8 * s, va_list * args)
67 : {
68 0 : ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *);
69 : u64 random, cumulative;
70 0 : random = cumulative = 0;
71 0 : if (pot0)
72 : {
73 0 : random = clib_net_to_host_u64 (pot0->random);
74 0 : cumulative = clib_net_to_host_u64 (pot0->cumulative);
75 : }
76 :
77 0 : s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x",
78 0 : random, cumulative, pot0 ? pot0->reserved_profile_id : ~0);
79 0 : return s;
80 : }
81 :
82 : u8 *
83 0 : ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt)
84 : {
85 : ioam_pot_option_t *pot;
86 :
87 0 : s = format (s, " POT opt present\n");
88 0 : pot = (ioam_pot_option_t *) opt;
89 0 : s = format (s, " %U\n", format_ioam_pot, pot);
90 0 : return (s);
91 : }
92 :
93 : int
94 0 : ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b,
95 : ip6_header_t *ip,
96 : ip6_hop_by_hop_option_t *opt0)
97 : {
98 : ioam_pot_option_t * pot0;
99 0 : u64 random = 0, cumulative = 0;
100 0 : int rv = 0;
101 : u8 pot_profile_index;
102 0 : pot_profile *pot_profile = 0, *new_profile = 0;
103 0 : u8 pot_encap = 0;
104 :
105 0 : pot0 = (ioam_pot_option_t *) opt0;
106 0 : pot_encap = (pot0->random == 0);
107 0 : pot_profile_index = pot_profile_get_active_id();
108 0 : pot_profile = pot_profile_get_active();
109 0 : if (pot_encap && PREDICT_FALSE(!pot_profile))
110 : {
111 0 : ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
112 0 : return(-1);
113 : }
114 0 : if (pot_encap)
115 : {
116 0 : pot0->reserved_profile_id =
117 0 : pot_profile_index & PROFILE_ID_MASK;
118 0 : pot_profile_incr_usage_stats(pot_profile);
119 : }
120 : else
121 : { /* Non encap node */
122 0 : if (PREDICT_FALSE(pot0->reserved_profile_id !=
123 : pot_profile_index || pot_profile == 0))
124 : {
125 : /* New profile announced by encap node. */
126 : new_profile =
127 0 : pot_profile_find(pot0->reserved_profile_id);
128 0 : if (PREDICT_FALSE(new_profile == 0 ||
129 : new_profile->valid == 0))
130 : {
131 0 : ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
132 0 : return(-1);
133 : }
134 : else
135 : {
136 0 : pot_profile_index = pot0->reserved_profile_id;
137 0 : pot_profile = new_profile;
138 0 : pot_profile_set_active(pot_profile_index);
139 0 : pot_profile_reset_usage_stats(pot_profile);
140 : }
141 : }
142 0 : pot_profile_incr_usage_stats(pot_profile);
143 : }
144 :
145 0 : if (pot0->random == 0)
146 : {
147 0 : pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile));
148 0 : pot0->cumulative = 0;
149 : }
150 0 : random = clib_net_to_host_u64(pot0->random);
151 0 : cumulative = clib_net_to_host_u64(pot0->cumulative);
152 0 : pot0->cumulative = clib_host_to_net_u64(
153 : pot_update_cumulative(pot_profile,
154 : cumulative,
155 : random));
156 0 : ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1);
157 :
158 0 : return (rv);
159 : }
160 :
161 : int
162 0 : ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip,
163 : ip6_hop_by_hop_option_t *opt0)
164 : {
165 : ioam_pot_option_t * pot0;
166 0 : u64 random = 0;
167 0 : u64 cumulative = 0;
168 0 : int rv = 0;
169 0 : pot_profile *pot_profile = 0;
170 0 : u8 result = 0;
171 :
172 0 : pot0 = (ioam_pot_option_t *) opt0;
173 0 : random = clib_net_to_host_u64(pot0->random);
174 0 : cumulative = clib_net_to_host_u64(pot0->cumulative);
175 0 : pot_profile = pot_profile_get_active();
176 0 : result = pot_validate (pot_profile,
177 : cumulative, random);
178 :
179 0 : if (result == 1)
180 : {
181 0 : ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1);
182 : }
183 : else
184 : {
185 0 : ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1);
186 : }
187 0 : return (rv);
188 : }
189 :
190 0 : int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 *rewrite_size)
191 : {
192 : ioam_pot_option_t * pot_option;
193 0 : if (rewrite_string && *rewrite_size == sizeof(ioam_pot_option_t))
194 : {
195 0 : pot_option = (ioam_pot_option_t *)rewrite_string;
196 0 : pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
197 : | HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
198 0 : pot_option->hdr.length = sizeof (ioam_pot_option_t) -
199 : sizeof (ip6_hop_by_hop_option_t);
200 0 : return(0);
201 : }
202 0 : return(-1);
203 : }
204 :
205 : static clib_error_t *
206 0 : ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm,
207 : unformat_input_t * input,
208 : vlib_cli_command_t * cmd)
209 : {
210 0 : ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
211 0 : u8 *s = 0;
212 0 : int i = 0;
213 :
214 0 : for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++)
215 : {
216 0 : s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i],
217 : hm->counters[i]);
218 : }
219 :
220 0 : vlib_cli_output(vm, "%v", s);
221 0 : vec_free(s);
222 0 : return 0;
223 : }
224 :
225 :
226 176567 : VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = {
227 : .path = "show ioam pot",
228 : .short_help = "iOAM pot statistics",
229 : .function = ip6_show_ioam_pot_cmd_fn,
230 : };
231 :
232 :
233 : static clib_error_t *
234 559 : ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm)
235 : {
236 559 : ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main;
237 :
238 559 : hm->vlib_main = vm;
239 559 : hm->vnet_main = vnet_get_main();
240 559 : clib_memset(hm->counters, 0, sizeof(hm->counters));
241 :
242 559 : if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler,
243 : ip6_hbh_ioam_proof_of_transit_trace_handler) < 0)
244 0 : return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed"));
245 :
246 559 : if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
247 : sizeof(ioam_pot_option_t),
248 : ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0)
249 0 : return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed"));
250 :
251 559 : if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
252 : ip6_hbh_ioam_proof_of_transit_pop_handler) < 0)
253 0 : return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed"));
254 :
255 559 : return (0);
256 : }
257 :
258 : /* *INDENT-OFF* */
259 1119 : VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init) =
260 : {
261 : .runs_after = VLIB_INITS("ip6_hop_by_hop_ioam_init"),
262 : };
263 : /* *INDENT-OFF* */
|