vlib: improvement to automatic core pinning
[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 <vnet/ip/ip6_hop_by_hop.h>
28
29 #include "ioam_cache.h"
30
31 /* define message IDs */
32 #include <ioam/ip6/ioam_cache.api_enum.h>
33 #include <ioam/ip6/ioam_cache.api_types.h>
34
35 #define REPLY_MSG_ID_BASE cm->msg_id_base
36 #include <vlibapi/api_helper_macros.h>
37
38 ioam_cache_main_t ioam_cache_main;
39
40 static u8 *
41 ioam_e2e_id_trace_handler (u8 * s, ip6_hop_by_hop_option_t * opt)
42 {
43   ioam_e2e_id_option_t *e2e = (ioam_e2e_id_option_t *) opt;
44
45   if (e2e)
46     {
47       s =
48         format (s, "IP6_HOP_BY_HOP E2E ID = %U\n", format_ip6_address,
49                 &(e2e->id));
50     }
51
52
53   return s;
54 }
55
56 static u8 *
57 ioam_e2e_cache_trace_handler (u8 * s, ip6_hop_by_hop_option_t * opt)
58 {
59   ioam_e2e_cache_option_t *e2e = (ioam_e2e_cache_option_t *) opt;
60
61   if (e2e)
62     {
63       s =
64         format (s, "IP6_HOP_BY_HOP E2E CACHE = pool:%d idx:%d\n",
65                 e2e->pool_id, e2e->pool_index);
66     }
67
68
69   return s;
70 }
71
72 /* Action function shared between message handler and debug CLI */
73 int
74 ioam_cache_ip6_enable_disable (ioam_cache_main_t * em,
75                                ip6_address_t * sr_localsid, u8 is_disable)
76 {
77   vlib_main_t *vm = em->vlib_main;
78
79   if (is_disable == 0)
80     {
81       ioam_cache_table_init (vm);
82       em->sr_localsid_cache.as_u64[0] = sr_localsid->as_u64[0];
83       em->sr_localsid_cache.as_u64[1] = sr_localsid->as_u64[1];
84       ip6_hbh_set_next_override (em->cache_hbh_slot);
85       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID,
86                                0, ioam_e2e_id_trace_handler);
87       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID,
88                                0, ioam_e2e_cache_trace_handler);
89
90     }
91   else
92     {
93       ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP);
94       ioam_cache_table_destroy (vm);
95       em->sr_localsid_cache.as_u64[0] = 0;
96       em->sr_localsid_cache.as_u64[1] = 0;
97       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID);
98       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID);
99     }
100
101   return 0;
102 }
103
104 /* Action function shared between message handler and debug CLI */
105 int
106 ioam_tunnel_select_ip6_enable_disable (ioam_cache_main_t * em,
107                                        u8 criteria,
108                                        u8 no_of_responses,
109                                        ip6_address_t * sr_localsid,
110                                        u8 is_disable)
111 {
112   vlib_main_t *vm = em->vlib_main;
113
114   if (is_disable == 0)
115     {
116       ioam_cache_ts_table_init (vm);
117       em->criteria_oneway = criteria;
118       em->wait_for_responses = no_of_responses;
119       em->sr_localsid_ts.as_u64[0] = sr_localsid->as_u64[0];
120       em->sr_localsid_ts.as_u64[1] = sr_localsid->as_u64[1];
121       ip6_hbh_set_next_override (em->ts_hbh_slot);
122       ip6_ioam_ts_cache_set_rewrite ();
123       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID,
124                                0, ioam_e2e_id_trace_handler);
125       ip6_hbh_register_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID,
126                                0, ioam_e2e_cache_trace_handler);
127
128       /* Turn on the cleanup process */
129       //      vlib_process_signal_event (vm, em->cleanup_process_node_index, 1, 0);
130     }
131   else
132     {
133       ioam_cache_ts_timer_node_enable (vm, 0);
134       ip6_hbh_set_next_override (IP6_LOOKUP_NEXT_POP_HOP_BY_HOP);
135       em->sr_localsid_ts.as_u64[0] = 0;
136       em->sr_localsid_ts.as_u64[1] = 0;
137       ioam_cache_ts_table_destroy (vm);
138       ip6_ioam_ts_cache_cleanup_rewrite ();
139       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE_ID);
140       ip6_hbh_unregister_option (HBH_OPTION_TYPE_IOAM_E2E_CACHE_ID);
141     }
142
143   return 0;
144 }
145
146 /* API message handler */
147 static void vl_api_ioam_cache_ip6_enable_disable_t_handler
148   (vl_api_ioam_cache_ip6_enable_disable_t * mp)
149 {
150   vl_api_ioam_cache_ip6_enable_disable_reply_t *rmp;
151   ioam_cache_main_t *cm = &ioam_cache_main;
152   ip6_address_t sr_localsid;
153   int rv;
154
155   sr_localsid.as_u64[0] = 0;
156   sr_localsid.as_u64[1] = 0;
157   rv =
158     ioam_cache_ip6_enable_disable (cm, &sr_localsid, (int) (mp->is_disable));
159   REPLY_MACRO (VL_API_IOAM_CACHE_IP6_ENABLE_DISABLE_REPLY);
160 }
161
162 static clib_error_t *
163 set_ioam_cache_command_fn (vlib_main_t * vm,
164                            unformat_input_t * input, vlib_cli_command_t * cmd)
165 {
166   ioam_cache_main_t *em = &ioam_cache_main;
167   u8 is_disable = 0;
168   ip6_address_t sr_localsid;
169   u8 address_set = 0;
170
171   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
172     {
173       if (unformat (input, "disable"))
174         is_disable = 1;
175       else if (!address_set
176                && unformat (input, "sr_localsid %U", unformat_ip6_address,
177                             &sr_localsid))
178         address_set = 1;
179       else
180         break;
181     }
182
183   if (is_disable == 0 && !address_set)
184     return clib_error_return (0, "Error: SRv6 LocalSID address is mandatory");
185
186   ioam_cache_ip6_enable_disable (em, &sr_localsid, is_disable);
187
188   return 0;
189 }
190
191 /* *INDENT_OFF* */
192 VLIB_CLI_COMMAND (set_ioam_cache_command, static) =
193 {
194 .path = "set ioam ip6 cache",.short_help =
195     "set ioam ip6 cache sr_localsid <ip6 address> [disable]",.function =
196     set_ioam_cache_command_fn};
197 /* *INDENT_ON* */
198
199 #define IOAM_TS_WAIT_FOR_RESPONSES 3
200 static clib_error_t *
201 set_ioam_tunnel_select_command_fn (vlib_main_t * vm,
202                                    unformat_input_t * input,
203                                    vlib_cli_command_t * cmd)
204 {
205   ioam_cache_main_t *em = &ioam_cache_main;
206   u8 is_disable = 0;
207   u8 one_way = 0;
208   ip6_address_t sr_localsid;
209   u8 address_set = 0;
210   u8 no_of_responses = IOAM_TS_WAIT_FOR_RESPONSES;
211
212   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
213     {
214       if (unformat (input, "disable"))
215         is_disable = 1;
216       else if (unformat (input, "rtt"))
217         one_way = 0;
218       else if (unformat (input, "oneway"))
219         one_way = 1;
220       else if (unformat (input, "wait_for_responses %d", &no_of_responses))
221         ;
222       else if (!address_set
223                && unformat (input, "sr_localsid %U", unformat_ip6_address,
224                             &sr_localsid))
225         address_set = 1;
226       else
227         break;
228     }
229   if (is_disable == 0 && !address_set)
230     return clib_error_return (0,
231                               "Error: SRv6 LocalSID address is mandatory to receive response.");
232
233   ioam_tunnel_select_ip6_enable_disable (em, one_way, no_of_responses,
234                                          &sr_localsid, is_disable);
235
236   return 0;
237 }
238
239 /* *INDENT_OFF* */
240 VLIB_CLI_COMMAND (set_ioam_cache_ts_command, static) =
241 {
242 .path = "set ioam ip6 sr-tunnel-select",.short_help =
243     "set ioam ip6 sr-tunnel-select [disable] [oneway|rtt] [wait_for_responses <n|default 3>] \
244   [sr_localsid <ip6 address>]",.function = set_ioam_tunnel_select_command_fn};
245 /* *INDENT_ON* */
246
247 static void
248 ioam_cache_table_print (vlib_main_t * vm, u8 verbose)
249 {
250   ioam_cache_main_t *cm = &ioam_cache_main;
251   ioam_cache_entry_t *entry = 0;
252   ioam_cache_ts_entry_t *ts_entry = 0;
253   int no_of_threads = vec_len (vlib_worker_threads);
254   int i;
255
256   pool_foreach (entry, cm->ioam_rewrite_pool)
257   {
258     vlib_cli_output (vm, "%U", format_ioam_cache_entry, entry);
259   }
260
261   if (cm->ts_stats)
262     for (i = 0; i < no_of_threads; i++)
263       {
264         vlib_cli_output (vm, "Number of entries in thread-%d selection pool: %lu\n \
265                           (pool found to be full: %lu times)", i,
266                          cm->ts_stats[i].inuse, cm->ts_stats[i].add_failed);
267
268         if (verbose == 1)
269           vlib_worker_thread_barrier_sync (vm);
270         pool_foreach (ts_entry, cm->ioam_ts_pool[i])
271         {
272           vlib_cli_output (vm, "%U", format_ioam_cache_ts_entry, ts_entry,
273                            (u32) i);
274         }
275         vlib_worker_thread_barrier_release (vm);
276       }
277
278 }
279
280 static clib_error_t *
281 show_ioam_cache_command_fn (vlib_main_t * vm,
282                             unformat_input_t * input,
283                             vlib_cli_command_t * cmd)
284 {
285   u8 verbose = 0;
286
287   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
288     {
289       if (unformat (input, "verbose"))
290         verbose = 1;
291       else
292         return clib_error_return (0, "unknown input `%U'",
293                                   format_unformat_error, input);
294     }
295   ioam_cache_table_print (vm, verbose);
296
297
298   return 0;
299 }
300
301 /* *INDENT_OFF* */
302 VLIB_CLI_COMMAND (show_ioam_cache_command, static) =
303 {
304 .path = "show ioam ip6 cache",.short_help =
305     "show ioam ip6 cache [verbose]",.function = show_ioam_cache_command_fn};
306 /* *INDENT_ON* */
307
308 #include <ioam/ip6/ioam_cache.api.c>
309 static clib_error_t *
310 ioam_cache_init (vlib_main_t * vm)
311 {
312   vlib_node_t *node;
313   ioam_cache_main_t *em = &ioam_cache_main;
314   u32 cache_node_index = ioam_cache_node.index;
315   u32 ts_node_index = ioam_cache_ts_node.index;
316   vlib_node_t *ip6_hbyh_node = NULL, *ip6_hbh_pop_node = NULL, *error_node =
317     NULL;
318
319   clib_memset (&ioam_cache_main, 0, sizeof (ioam_cache_main));
320   /* Ask for a correctly-sized block of API message decode slots */
321   em->msg_id_base = setup_message_id_table ();
322
323   /* Hook this node to ip6-hop-by-hop */
324   ip6_hbyh_node = vlib_get_node_by_name (vm, (u8 *) "ip6-hop-by-hop");
325   em->cache_hbh_slot =
326     vlib_node_add_next (vm, ip6_hbyh_node->index, cache_node_index);
327   em->ts_hbh_slot =
328     vlib_node_add_next (vm, ip6_hbyh_node->index, ts_node_index);
329
330   ip6_hbh_pop_node = vlib_get_node_by_name (vm, (u8 *) "ip6-pop-hop-by-hop");
331   em->ip6_hbh_pop_node_index = ip6_hbh_pop_node->index;
332
333   error_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
334   em->error_node_index = error_node->index;
335   em->vlib_main = vm;
336
337   node = vlib_get_node_by_name (vm, (u8 *) "ip6-add-from-cache-hop-by-hop");
338   em->ip6_add_from_cache_hbh_node_index = node->index;
339
340   node = vlib_get_node_by_name (vm, (u8 *) "ip6-add-syn-hop-by-hop");
341   em->ip6_reset_ts_hbh_node_index = node->index;
342
343   return 0;
344 }
345
346 VLIB_INIT_FUNCTION (ioam_cache_init);
347
348 /*
349  * fd.io coding-style-patch-verification: ON
350  *
351  * Local Variables:
352  * eval: (c-set-style "gnu")
353  * End:
354  */