4c9997f492374fe0f727e11828ea2e5096198c78
[vpp.git] / src / plugins / ioam / ip6 / ioam_cache.c
1 /*
2  * Copyright (c) 2017 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 /*
16  *------------------------------------------------------------------
17  * ioam_cache.c - ioam ip6 API / debug CLI handling
18  *------------------------------------------------------------------
19  */
20
21 #include <vnet/vnet.h>
22 #include <vnet/plugin/plugin.h>
23 #include <ioam/ip6/ioam_cache.h>
24
25 #include <vlibapi/api.h>
26 #include <vlibmemory/api.h>
27 #include <vlibsocket/api.h>
28 #include <vnet/ip/ip6_hop_by_hop.h>
29
30 #include "ioam_cache.h"
31
32 /* define message IDs */
33 #include <ioam/ip6/ioam_cache_msg_enum.h>
34
35 /* define message structures */
36 #define vl_typedefs
37 #include <ioam/ip6/ioam_cache_all_api_h.h>
38 #undef vl_typedefs
39
40 /* define generated endian-swappers */
41 #define vl_endianfun
42 #include <ioam/ip6/ioam_cache_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
47 #define vl_printfun
48 #include <ioam/ip6/ioam_cache_all_api_h.h>
49 #undef vl_printfun
50
51 /* Get the API version number */
52 #define vl_api_version(n,v) static u32 api_version=(v);
53 #include <ioam/ip6/ioam_cache_all_api_h.h>
54 #undef vl_api_version
55
56 #define REPLY_MSG_ID_BASE cm->msg_id_base
57 #include <vlibapi/api_helper_macros.h>
58
59 /* List of message types that this plugin understands */
60 #define foreach_ioam_cache_plugin_api_msg                        \
61 _(IOAM_CACHE_IP6_ENABLE_DISABLE, ioam_cache_ip6_enable_disable)
62
63 static u8 *
64 ioam_e2e_id_trace_handler (u8 * s, ip6_hop_by_hop_option_t * opt)
65 {
66   ioam_e2e_id_option_t *e2e = (ioam_e2e_id_option_t *) opt;
67
68   if (e2e)
69     {
70       s =
71         format (s, "IP6_HOP_BY_HOP E2E ID = %U\n", format_ip6_address,
72                 &(e2e->id));
73     }
74
75
76   return s;
77 }
78
79 static u8 *
80 ioam_e2e_cache_trace_handler (u8 * s, ip6_hop_by_hop_option_t * opt)
81 {
82   ioam_e2e_cache_option_t *e2e = (ioam_e2e_cache_option_t *) opt;
83
84   if (e2e)
85     {
86       s =
87         format (s, "IP6_HOP_BY_HOP E2E CACHE = pool:%d idx:%d\n",
88                 e2e->pool_id, e2e->pool_index);
89     }
90
91
92   return s;
93 }
94
95 /* Action function shared between message handler and debug CLI */
96 int
97 ioam_cache_ip6_enable_disable (ioam_cache_main_t * em,
98                                ip6_address_t * sr_localsid, u8 is_disable)
99 {
100   vlib_main_t *vm = em->vlib_main;
101
102   if (is_disable == 0)
103     {
104       ioam_cache_table_init (vm);
105       em->sr_localsid_cache.as_u64[0] = sr_localsid->as_u64[0];
106       em->sr_localsid_cache.as_u64[1] = sr_localsid->as_u64[1];
107       ip6_hbh_set_next_override (em->cache_hbh_slot);
108       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID,
109                                0, ioam_e2e_id_trace_handler);
110       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID,
111                                0, ioam_e2e_cache_trace_handler);
112
113     }
114   else
115     {
116       ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP);
117       ioam_cache_table_destroy (vm);
118       em->sr_localsid_cache.as_u64[0] = 0;
119       em->sr_localsid_cache.as_u64[1] = 0;
120       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID);
121       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID);
122     }
123
124   return 0;
125 }
126
127 /* Action function shared between message handler and debug CLI */
128 int
129 ioam_tunnel_select_ip6_enable_disable (ioam_cache_main_t * em,
130                                        u8 criteria,
131                                        u8 no_of_responses,
132                                        ip6_address_t * sr_localsid,
133                                        u8 is_disable)
134 {
135   vlib_main_t *vm = em->vlib_main;
136
137   if (is_disable == 0)
138     {
139       ioam_cache_ts_table_init (vm);
140       em->criteria_oneway = criteria;
141       em->wait_for_responses = no_of_responses;
142       em->sr_localsid_ts.as_u64[0] = sr_localsid->as_u64[0];
143       em->sr_localsid_ts.as_u64[1] = sr_localsid->as_u64[1];
144       ip6_hbh_set_next_override (em->ts_hbh_slot);
145       ip6_ioam_ts_cache_set_rewrite ();
146       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID,
147                                0, ioam_e2e_id_trace_handler);
148       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID,
149                                0, ioam_e2e_cache_trace_handler);
150
151       /* Turn on the cleanup process */
152       //      vlib_process_signal_event (vm, em->cleanup_process_node_index, 1, 0);
153     }
154   else
155     {
156       ioam_cache_ts_timer_node_enable (vm, 0);
157       ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP);
158       em->sr_localsid_ts.as_u64[0] = 0;
159       em->sr_localsid_ts.as_u64[1] = 0;
160       ioam_cache_ts_table_destroy (vm);
161       ip6_ioam_ts_cache_cleanup_rewrite ();
162       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID);
163       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID);
164     }
165
166   return 0;
167 }
168
169 /* API message handler */
170 static void vl_api_ioam_cache_ip6_enable_disable_t_handler
171   (vl_api_ioam_cache_ip6_enable_disable_t * mp)
172 {
173   vl_api_ioam_cache_ip6_enable_disable_reply_t *rmp;
174   ioam_cache_main_t *cm = &ioam_cache_main;
175   ip6_address_t sr_localsid;
176   int rv;
177
178   sr_localsid.as_u64[0] = 0;
179   sr_localsid.as_u64[1] = 0;
180   rv =
181     ioam_cache_ip6_enable_disable (cm, &sr_localsid, (int) (mp->is_disable));
182   REPLY_MACRO (VL_API_IOAM_CACHE_IP6_ENABLE_DISABLE_REPLY);
183 }
184
185 /* Set up the API message handling tables */
186 static clib_error_t *
187 ioam_cache_plugin_api_hookup (vlib_main_t * vm)
188 {
189   ioam_cache_main_t *sm = &ioam_cache_main;
190 #define _(N,n)                                                  \
191     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
192                            #n,                                  \
193                            vl_api_##n##_t_handler,              \
194                            vl_noop_handler,                     \
195                            vl_api_##n##_t_endian,               \
196                            vl_api_##n##_t_print,                \
197                            sizeof(vl_api_##n##_t), 1);
198   foreach_ioam_cache_plugin_api_msg;
199 #undef _
200
201   return 0;
202 }
203
204 #define vl_msg_name_crc_list
205 #include <ioam/ip6/ioam_cache_all_api_h.h>
206 #undef vl_msg_name_crc_list
207
208 static void
209 setup_message_id_table (ioam_cache_main_t * sm, api_main_t * am)
210 {
211 #define _(id,n,crc) \
212   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
213   foreach_vl_msg_name_crc_ioam_cache;
214 #undef _
215 }
216
217 static clib_error_t *
218 set_ioam_cache_command_fn (vlib_main_t * vm,
219                            unformat_input_t * input, vlib_cli_command_t * cmd)
220 {
221   ioam_cache_main_t *em = &ioam_cache_main;
222   u8 is_disable = 0;
223   ip6_address_t sr_localsid;
224   u8 address_set = 0;
225
226   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
227     {
228       if (unformat (input, "disable"))
229         is_disable = 1;
230       else if (!address_set
231                && unformat (input, "sr_localsid %U", unformat_ip6_address,
232                             &sr_localsid))
233         address_set = 1;
234       else
235         break;
236     }
237
238   if (is_disable == 0 && !address_set)
239     return clib_error_return (0, "Error: SRv6 LocalSID address is mandatory");
240
241   ioam_cache_ip6_enable_disable (em, &sr_localsid, is_disable);
242
243   return 0;
244 }
245
246 /* *INDENT_OFF* */
247 VLIB_CLI_COMMAND (set_ioam_cache_command, static) =
248 {
249 .path = "set ioam ip6 cache",.short_help =
250     "set ioam ip6 cache sr_localsid <ip6 address> [disable]",.function =
251     set_ioam_cache_command_fn};
252 /* *INDENT_ON* */
253
254 #define IOAM_TS_WAIT_FOR_RESPONSES 3
255 static clib_error_t *
256 set_ioam_tunnel_select_command_fn (vlib_main_t * vm,
257                                    unformat_input_t * input,
258                                    vlib_cli_command_t * cmd)
259 {
260   ioam_cache_main_t *em = &ioam_cache_main;
261   u8 is_disable = 0;
262   u8 one_way = 0;
263   ip6_address_t sr_localsid;
264   u8 address_set = 0;
265   u8 no_of_responses = IOAM_TS_WAIT_FOR_RESPONSES;
266
267   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
268     {
269       if (unformat (input, "disable"))
270         is_disable = 1;
271       else if (unformat (input, "rtt"))
272         one_way = 0;
273       else if (unformat (input, "oneway"))
274         one_way = 1;
275       else if (unformat (input, "wait_for_responses %d", &no_of_responses))
276         ;
277       else if (!address_set
278                && unformat (input, "sr_localsid %U", unformat_ip6_address,
279                             &sr_localsid))
280         address_set = 1;
281       else
282         break;
283     }
284   if (is_disable == 0 && !address_set)
285     return clib_error_return (0,
286                               "Error: SRv6 LocalSID address is mandatory to receive response.");
287
288   ioam_tunnel_select_ip6_enable_disable (em, one_way, no_of_responses,
289                                          &sr_localsid, is_disable);
290
291   return 0;
292 }
293
294 /* *INDENT_OFF* */
295 VLIB_CLI_COMMAND (set_ioam_cache_ts_command, static) =
296 {
297 .path = "set ioam ip6 sr-tunnel-select",.short_help =
298     "set ioam ip6 sr-tunnel-select [disable] [oneway|rtt] [wait_for_responses <n|default 3>] \
299   [sr_localsid <ip6 address>]",.function = set_ioam_tunnel_select_command_fn};
300 /* *INDENT_ON* */
301
302 static void
303 ioam_cache_table_print (vlib_main_t * vm, u8 verbose)
304 {
305   ioam_cache_main_t *cm = &ioam_cache_main;
306   ioam_cache_entry_t *entry = 0;
307   ioam_cache_ts_entry_t *ts_entry = 0;
308   int no_of_threads = vec_len (vlib_worker_threads);
309   int i;
310
311   pool_foreach (entry, cm->ioam_rewrite_pool, (
312                                                 {
313                                                 vlib_cli_output (vm, "%U",
314                                                                  format_ioam_cache_entry,
315                                                                  entry);
316                                                 }));
317
318   if (cm->ts_stats)
319     for (i = 0; i < no_of_threads; i++)
320       {
321         vlib_cli_output (vm, "Number of entries in thread-%d selection pool: %lu\n \
322                           (pool found to be full: %lu times)", i,
323                          cm->ts_stats[i].inuse, cm->ts_stats[i].add_failed);
324
325         if (verbose == 1)
326           vlib_worker_thread_barrier_sync (vm);
327         pool_foreach (ts_entry, cm->ioam_ts_pool[i], (
328                                                        {
329                                                        vlib_cli_output (vm,
330                                                                         "%U",
331                                                                         format_ioam_cache_ts_entry,
332                                                                         ts_entry,
333                                                                         (u32)
334                                                                         i);
335                                                        }
336                       ));
337         vlib_worker_thread_barrier_release (vm);
338       }
339
340 }
341
342 static clib_error_t *
343 show_ioam_cache_command_fn (vlib_main_t * vm,
344                             unformat_input_t * input,
345                             vlib_cli_command_t * cmd)
346 {
347   u8 verbose = 0;
348
349   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
350     {
351       if (unformat (input, "verbose"))
352         verbose = 1;
353     }
354   ioam_cache_table_print (vm, verbose);
355
356
357   return 0;
358 }
359
360 /* *INDENT_OFF* */
361 VLIB_CLI_COMMAND (show_ioam_cache_command, static) =
362 {
363 .path = "show ioam ip6 cache",.short_help =
364     "show ioam ip6 cache [verbose]",.function = show_ioam_cache_command_fn};
365 /* *INDENT_ON* */
366
367 static clib_error_t *
368 ioam_cache_init (vlib_main_t * vm)
369 {
370   ioam_cache_main_t *em = &ioam_cache_main;
371   clib_error_t *error = 0;
372   u8 *name;
373   u32 cache_node_index = ioam_cache_node.index;
374   u32 ts_node_index = ioam_cache_ts_node.index;
375   vlib_node_t *ip6_hbyh_node = NULL, *ip6_hbh_pop_node = NULL, *error_node =
376     NULL;
377
378   name = format (0, "ioam_cache_%08x%c", api_version, 0);
379
380   memset (&ioam_cache_main, 0, sizeof (ioam_cache_main));
381   /* Ask for a correctly-sized block of API message decode slots */
382   em->msg_id_base = vl_msg_api_get_msg_ids
383     ((char *) name, VL_MSG_FIRST_AVAILABLE);
384
385   error = ioam_cache_plugin_api_hookup (vm);
386
387   /* Add our API messages to the global name_crc hash table */
388   setup_message_id_table (em, &api_main);
389
390   /* Hook this node to ip6-hop-by-hop */
391   ip6_hbyh_node = vlib_get_node_by_name (vm, (u8 *) "ip6-hop-by-hop");
392   em->cache_hbh_slot =
393     vlib_node_add_next (vm, ip6_hbyh_node->index, cache_node_index);
394   em->ts_hbh_slot =
395     vlib_node_add_next (vm, ip6_hbyh_node->index, ts_node_index);
396
397   ip6_hbh_pop_node = vlib_get_node_by_name (vm, (u8 *) "ip6-pop-hop-by-hop");
398   em->ip6_hbh_pop_node_index = ip6_hbh_pop_node->index;
399
400   error_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
401   em->error_node_index = error_node->index;
402   em->vlib_main = vm;
403
404   vec_free (name);
405
406   return error;
407 }
408
409 VLIB_INIT_FUNCTION (ioam_cache_init);
410
411 /*
412  * fd.io coding-style-patch-verification: ON
413  *
414  * Local Variables:
415  * eval: (c-set-style "gnu")
416  * End:
417  */