Line data Source code
1 : /*
2 : * nsh_api.c - nsh mapping api
3 : *
4 : * Copyright (c) 2019 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #include <vnet/vnet.h>
18 : #include <vnet/plugin/plugin.h>
19 : #include <nsh/nsh.h>
20 :
21 : #include <vlibapi/api.h>
22 : #include <vlibmemory/api.h>
23 : #include <vpp/app/version.h>
24 : #include <vlibapi/api_helper_macros.h>
25 :
26 : #include <plugins/nsh/nsh.api_enum.h>
27 : #include <plugins/nsh/nsh.api_types.h>
28 :
29 : /**
30 : * @brief CLI function for NSH admin up/down
31 : *
32 : * @param *vnm
33 : * @param nsh_hw_if
34 : * @param flag
35 : *
36 : * @return *rc
37 : *
38 : */
39 : static clib_error_t *
40 0 : nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
41 : {
42 0 : if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
43 0 : vnet_hw_interface_set_flags (vnm, nsh_hw_if,
44 : VNET_HW_INTERFACE_FLAG_LINK_UP);
45 : else
46 0 : vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
47 :
48 0 : return 0;
49 : }
50 :
51 : /**
52 : * @brief Naming for NSH tunnel
53 : *
54 : * @param *s formatting string
55 : * @param *args
56 : *
57 : * @return *s formatted string
58 : *
59 : */
60 : static u8 *
61 0 : format_nsh_name (u8 * s, va_list * args)
62 : {
63 0 : u32 dev_instance = va_arg (*args, u32);
64 0 : return format (s, "nsh_tunnel%d", dev_instance);
65 : }
66 :
67 : /* *INDENT-OFF* */
68 5183 : VNET_DEVICE_CLASS (nsh_device_class, static) = {
69 : .name = "NSH",
70 : .format_device_name = format_nsh_name,
71 : .admin_up_down_function = nsh_interface_admin_up_down,
72 : };
73 : /* *INDENT-ON* */
74 :
75 0 : static void send_nsh_entry_details
76 : (nsh_entry_t * t, vl_api_registration_t * rp, u32 context)
77 : {
78 : vl_api_nsh_entry_details_t *rmp;
79 0 : nsh_main_t *nm = &nsh_main;
80 :
81 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
82 0 : clib_memset (rmp, 0, sizeof (*rmp));
83 :
84 0 : rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base);
85 0 : rmp->ver_o_c = t->nsh_base.ver_o_c;
86 0 : rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 |
87 0 : (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6;
88 0 : rmp->length = t->nsh_base.length & NSH_LEN_MASK;
89 0 : rmp->md_type = t->nsh_base.md_type;
90 0 : rmp->next_protocol = t->nsh_base.next_protocol;
91 0 : rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi);
92 :
93 0 : if (t->nsh_base.md_type == 1)
94 : {
95 0 : rmp->tlv_length = 4;
96 0 : rmp->c1 = htonl (t->md.md1_data.c1);
97 0 : rmp->c2 = htonl (t->md.md1_data.c2);
98 0 : rmp->c3 = htonl (t->md.md1_data.c3);
99 0 : rmp->c4 = htonl (t->md.md1_data.c4);
100 : }
101 0 : else if (t->nsh_base.md_type == 2)
102 : {
103 0 : rmp->tlv_length = t->tlvs_len;
104 0 : clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len);
105 : }
106 :
107 0 : rmp->context = context;
108 :
109 0 : vl_api_send_msg (rp, (u8 *) rmp);
110 0 : }
111 :
112 0 : static void send_nsh_map_details
113 : (nsh_map_t * t, vl_api_registration_t * rp, u32 context)
114 : {
115 : vl_api_nsh_map_details_t *rmp;
116 0 : nsh_main_t *nm = &nsh_main;
117 :
118 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
119 0 : clib_memset (rmp, 0, sizeof (*rmp));
120 :
121 0 : rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base);
122 0 : rmp->nsp_nsi = htonl (t->nsp_nsi);
123 0 : rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi);
124 0 : rmp->nsh_action = htonl (t->nsh_action);
125 0 : rmp->sw_if_index = htonl (t->sw_if_index);
126 0 : rmp->rx_sw_if_index = htonl (t->rx_sw_if_index);
127 0 : rmp->next_node = htonl (t->next_node);
128 :
129 0 : rmp->context = context;
130 :
131 0 : vl_api_send_msg (rp, (u8 *) rmp);
132 0 : }
133 :
134 : static void
135 0 : vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp)
136 : {
137 0 : nsh_main_t *nm = &nsh_main;
138 : nsh_map_t *t;
139 : u32 map_index;
140 : vl_api_registration_t *rp;
141 :
142 0 : rp = vl_api_client_index_to_registration (mp->client_index);
143 0 : if (rp == 0)
144 0 : return;
145 :
146 0 : map_index = ntohl (mp->map_index);
147 :
148 0 : if (~0 == map_index)
149 : {
150 0 : pool_foreach (t, nm->nsh_mappings)
151 : {
152 0 : send_nsh_map_details (t, rp, mp->context);
153 : }
154 : }
155 : else
156 : {
157 0 : if (map_index >= vec_len (nm->nsh_mappings))
158 : {
159 0 : return;
160 : }
161 0 : t = &nm->nsh_mappings[map_index];
162 0 : send_nsh_map_details (t, rp, mp->context);
163 : }
164 : }
165 :
166 : /** API message handler */
167 : static void
168 0 : vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp)
169 : {
170 : vl_api_nsh_add_del_map_reply_t *rmp;
171 : int rv;
172 0 : nsh_add_del_map_args_t _a = { 0 }, *a = &_a;
173 0 : u32 map_index = ~0;
174 :
175 0 : a->is_add = mp->is_add;
176 0 : a->map.nsp_nsi = ntohl (mp->nsp_nsi);
177 0 : a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi);
178 0 : a->map.nsh_action = ntohl (mp->nsh_action);
179 0 : a->map.sw_if_index = ntohl (mp->sw_if_index);
180 0 : a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index);
181 0 : a->map.next_node = ntohl (mp->next_node);
182 :
183 0 : rv = nsh_add_del_map (a, &map_index);
184 :
185 0 : if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
186 0 : | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
187 : {
188 0 : rv = nsh_add_del_proxy_session (a);
189 : }
190 :
191 0 : REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, (
192 : {
193 : rmp->map_index =
194 : htonl (map_index);
195 : }
196 : ));
197 : }
198 :
199 : int
200 0 : nsh_header_rewrite (nsh_entry_t * nsh_entry)
201 : {
202 0 : u8 *rw = 0;
203 0 : int len = 0;
204 : nsh_base_header_t *nsh_base;
205 : nsh_md1_data_t *nsh_md1;
206 0 : nsh_main_t *nm = &nsh_main;
207 : nsh_md2_data_t *opt0;
208 : nsh_md2_data_t *limit0;
209 : nsh_md2_data_t *nsh_md2;
210 0 : nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
211 0 : u8 old_option_size = 0;
212 0 : u8 new_option_size = 0;
213 :
214 0 : vec_free (nsh_entry->rewrite);
215 0 : if (nsh_entry->nsh_base.md_type == 1)
216 : {
217 0 : len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t);
218 : }
219 0 : else if (nsh_entry->nsh_base.md_type == 2)
220 : {
221 : /* set to maxim, maybe dataplane will add more TLVs */
222 0 : len = MAX_NSH_HEADER_LEN;
223 : }
224 0 : vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
225 0 : clib_memset (rw, 0, len);
226 :
227 0 : nsh_base = (nsh_base_header_t *) rw;
228 0 : nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
229 0 : nsh_base->length = nsh_entry->nsh_base.length;
230 0 : nsh_base->md_type = nsh_entry->nsh_base.md_type;
231 0 : nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
232 0 : nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi);
233 :
234 0 : if (nsh_base->md_type == 1)
235 : {
236 0 : nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t));
237 0 : nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1);
238 0 : nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2);
239 0 : nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3);
240 0 : nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4);
241 0 : nsh_entry->rewrite_size = 24;
242 : }
243 0 : else if (nsh_base->md_type == 2)
244 : {
245 0 : opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data);
246 0 : limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
247 :
248 0 : nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t));
249 0 : nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
250 :
251 0 : while (opt0 < limit0)
252 : {
253 0 : old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
254 : /* round to 4-byte */
255 0 : old_option_size = ((old_option_size + 3) >> 2) << 2;
256 :
257 0 : nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
258 0 : if (nsh_option == NULL)
259 : {
260 0 : goto next_tlv_md2;
261 : }
262 :
263 0 : if (nm->add_options[nsh_option->option_id] != NULL)
264 : {
265 0 : if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2,
266 : &new_option_size))
267 : {
268 0 : goto next_tlv_md2;
269 : }
270 :
271 : /* round to 4-byte */
272 0 : new_option_size = ((new_option_size + 3) >> 2) << 2;
273 :
274 0 : nsh_entry->rewrite_size += new_option_size;
275 0 : nsh_md2 =
276 0 : (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
277 0 : opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
278 : }
279 : else
280 : {
281 0 : next_tlv_md2:
282 0 : opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
283 : }
284 :
285 : }
286 : }
287 :
288 0 : nsh_entry->rewrite = rw;
289 0 : nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
290 0 : ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
291 :
292 0 : return 0;
293 : }
294 :
295 : extern vnet_hw_interface_class_t nsh_hw_class;
296 :
297 : /**
298 : * Action function to add or del an nsh map.
299 : * Shared by both CLI and binary API
300 : **/
301 : int
302 0 : nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp)
303 : {
304 0 : nsh_main_t *nm = &nsh_main;
305 0 : vnet_main_t *vnm = nm->vnet_main;
306 0 : nsh_map_t *map = 0;
307 : u32 key, *key_copy;
308 : uword *entry;
309 : hash_pair_t *hp;
310 0 : u32 map_index = ~0;
311 : vnet_hw_interface_t *hi;
312 0 : u32 nsh_hw_if = ~0;
313 0 : u32 nsh_sw_if = ~0;
314 :
315 : /* net order, so data plane could use nsh header to lookup directly */
316 0 : key = clib_host_to_net_u32 (a->map.nsp_nsi);
317 :
318 0 : entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
319 :
320 0 : if (a->is_add)
321 : {
322 : /* adding an entry, must not already exist */
323 0 : if (entry)
324 0 : return -1; //TODO API_ERROR_INVALID_VALUE;
325 :
326 0 : pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
327 0 : clib_memset (map, 0, sizeof (*map));
328 :
329 : /* copy from arg structure */
330 0 : map->nsp_nsi = a->map.nsp_nsi;
331 0 : map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
332 0 : map->nsh_action = a->map.nsh_action;
333 0 : map->sw_if_index = a->map.sw_if_index;
334 0 : map->rx_sw_if_index = a->map.rx_sw_if_index;
335 0 : map->next_node = a->map.next_node;
336 0 : map->adj_index = a->map.adj_index;
337 :
338 :
339 0 : key_copy = clib_mem_alloc (sizeof (*key_copy));
340 0 : clib_memcpy (key_copy, &key, sizeof (*key_copy));
341 :
342 0 : hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings);
343 0 : map_index = map - nm->nsh_mappings;
344 :
345 0 : if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0)
346 : {
347 0 : nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
348 0 : [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1];
349 0 : vec_dec_len (nm->free_nsh_tunnel_hw_if_indices, 1);
350 :
351 0 : hi = vnet_get_hw_interface (vnm, nsh_hw_if);
352 0 : hi->dev_instance = map_index;
353 0 : hi->hw_instance = hi->dev_instance;
354 : }
355 : else
356 : {
357 0 : nsh_hw_if = vnet_register_interface
358 : (vnm, nsh_device_class.index, map_index, nsh_hw_class.index,
359 : map_index);
360 0 : hi = vnet_get_hw_interface (vnm, nsh_hw_if);
361 0 : hi->output_node_index = nsh_aware_vnf_proxy_node.index;
362 : }
363 :
364 0 : map->nsh_hw_if = nsh_hw_if;
365 0 : map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
366 0 : vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if,
367 : ~0);
368 0 : nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
369 :
370 0 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
371 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
372 : }
373 : else
374 : {
375 0 : if (!entry)
376 0 : return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
377 :
378 0 : map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
379 :
380 0 : vnet_sw_interface_set_flags (vnm, map->nsh_sw_if,
381 : VNET_SW_INTERFACE_FLAG_ADMIN_DOWN);
382 0 : vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if);
383 0 : nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
384 :
385 0 : hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
386 0 : key_copy = (void *) (hp->key);
387 0 : hash_unset_mem (nm->nsh_mapping_by_key, &key);
388 0 : clib_mem_free (key_copy);
389 :
390 0 : pool_put (nm->nsh_mappings, map);
391 : }
392 :
393 0 : if (map_indexp)
394 0 : *map_indexp = map_index;
395 :
396 0 : return 0;
397 : }
398 :
399 : /**
400 : * Action function to add or del an nsh-proxy-session.
401 : * Shared by both CLI and binary API
402 : **/
403 : int
404 0 : nsh_add_del_proxy_session (nsh_add_del_map_args_t * a)
405 : {
406 0 : nsh_main_t *nm = &nsh_main;
407 0 : nsh_proxy_session_t *proxy = 0;
408 : nsh_proxy_session_by_key_t key, *key_copy;
409 : uword *entry;
410 : hash_pair_t *hp;
411 0 : u32 nsp = 0, nsi = 0;
412 :
413 0 : clib_memset (&key, 0, sizeof (key));
414 0 : key.transport_type = a->map.next_node;
415 0 : key.transport_index = a->map.sw_if_index;
416 :
417 0 : entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
418 :
419 0 : if (a->is_add)
420 : {
421 : /* adding an entry, must not already exist */
422 0 : if (entry)
423 0 : return -1; //TODO API_ERROR_INVALID_VALUE;
424 :
425 0 : pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
426 0 : clib_memset (proxy, 0, sizeof (*proxy));
427 :
428 : /* Nsi needs to minus 1 within NSH-Proxy */
429 0 : nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK;
430 0 : nsi = a->map.nsp_nsi & NSH_NSI_MASK;
431 0 : if (nsi == 0)
432 0 : return -1;
433 :
434 0 : nsi = nsi - 1;
435 : /* net order, so could use it to lookup nsh map table directly */
436 0 : proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi);
437 :
438 0 : key_copy = clib_mem_alloc (sizeof (*key_copy));
439 0 : clib_memcpy (key_copy, &key, sizeof (*key_copy));
440 :
441 0 : hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
442 : proxy - nm->nsh_proxy_sessions);
443 : }
444 : else
445 : {
446 0 : if (!entry)
447 0 : return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
448 :
449 0 : proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
450 0 : hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
451 0 : key_copy = (void *) (hp->key);
452 0 : hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
453 0 : clib_mem_free (key_copy);
454 :
455 0 : pool_put (nm->nsh_proxy_sessions, proxy);
456 : }
457 :
458 0 : return 0;
459 : }
460 :
461 : /**
462 : * Action function for adding an NSH entry
463 : * nsh_add_del_entry_args_t *a: host order
464 : */
465 : int
466 0 : nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp)
467 : {
468 0 : nsh_main_t *nm = &nsh_main;
469 0 : nsh_entry_t *nsh_entry = 0;
470 : u32 key, *key_copy;
471 : uword *entry_id;
472 : hash_pair_t *hp;
473 0 : u32 entry_index = ~0;
474 0 : u8 tlvs_len = 0;
475 0 : u8 *data = 0;
476 :
477 : /* host order, because nsh map table stores nsp_nsi in host order */
478 0 : key = a->nsh_entry.nsh_base.nsp_nsi;
479 :
480 0 : entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
481 :
482 0 : if (a->is_add)
483 : {
484 : /* adding an entry, must not already exist */
485 0 : if (entry_id)
486 0 : return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
487 :
488 0 : pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
489 0 : clib_memset (nsh_entry, 0, sizeof (*nsh_entry));
490 :
491 : /* copy from arg structure */
492 : #define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
493 0 : foreach_copy_nsh_base_hdr_field;
494 : #undef _
495 :
496 0 : if (a->nsh_entry.nsh_base.md_type == 1)
497 : {
498 0 : nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
499 0 : nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
500 0 : nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
501 0 : nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
502 : }
503 0 : else if (a->nsh_entry.nsh_base.md_type == 2)
504 : {
505 0 : vec_free (nsh_entry->tlvs_data);
506 0 : tlvs_len = a->nsh_entry.tlvs_len;
507 0 : vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
508 :
509 0 : clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len);
510 0 : nsh_entry->tlvs_data = data;
511 0 : nsh_entry->tlvs_len = tlvs_len;
512 0 : vec_free (a->nsh_entry.tlvs_data);
513 : }
514 :
515 0 : nsh_header_rewrite (nsh_entry);
516 :
517 0 : key_copy = clib_mem_alloc (sizeof (*key_copy));
518 0 : clib_memcpy (key_copy, &key, sizeof (*key_copy));
519 :
520 0 : hash_set_mem (nm->nsh_entry_by_key, key_copy,
521 : nsh_entry - nm->nsh_entries);
522 0 : entry_index = nsh_entry - nm->nsh_entries;
523 : }
524 : else
525 : {
526 0 : if (!entry_id)
527 0 : return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
528 :
529 0 : nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
530 0 : hp = hash_get_pair (nm->nsh_entry_by_key, &key);
531 0 : key_copy = (void *) (hp->key);
532 0 : hash_unset_mem (nm->nsh_entry_by_key, &key);
533 0 : clib_mem_free (key_copy);
534 :
535 0 : vec_free (nsh_entry->tlvs_data);
536 0 : vec_free (nsh_entry->rewrite);
537 0 : pool_put (nm->nsh_entries, nsh_entry);
538 : }
539 :
540 0 : if (entry_indexp)
541 0 : *entry_indexp = entry_index;
542 :
543 0 : return 0;
544 : }
545 :
546 :
547 : /** API message handler */
548 0 : static void vl_api_nsh_add_del_entry_t_handler
549 : (vl_api_nsh_add_del_entry_t * mp)
550 : {
551 : vl_api_nsh_add_del_entry_reply_t *rmp;
552 : int rv;
553 0 : nsh_add_del_entry_args_t _a = { 0 }, *a = &_a;
554 0 : u32 entry_index = ~0;
555 0 : u8 tlvs_len = 0;
556 0 : u8 *data = 0;
557 :
558 0 : a->is_add = mp->is_add;
559 0 : a->nsh_entry.nsh_base.ver_o_c =
560 0 : (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2);
561 0 : a->nsh_entry.nsh_base.length =
562 0 : (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6);
563 0 : a->nsh_entry.nsh_base.md_type = mp->md_type;
564 0 : a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
565 0 : a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi);
566 0 : if (mp->md_type == 1)
567 : {
568 0 : a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1);
569 0 : a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2);
570 0 : a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3);
571 0 : a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4);
572 : }
573 0 : else if (mp->md_type == 2)
574 : {
575 0 : tlvs_len = mp->tlv_length;
576 0 : vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
577 :
578 0 : clib_memcpy (data, mp->tlv, tlvs_len);
579 0 : a->nsh_entry.tlvs_data = data;
580 0 : a->nsh_entry.tlvs_len = tlvs_len;
581 : }
582 :
583 0 : rv = nsh_add_del_entry (a, &entry_index);
584 :
585 0 : REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, (
586 : {
587 : rmp->entry_index =
588 : htonl (entry_index);
589 : }
590 : ));
591 : }
592 :
593 : static void
594 0 : vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp)
595 : {
596 0 : nsh_main_t *nm = &nsh_main;
597 : nsh_entry_t *t;
598 : u32 entry_index;
599 : vl_api_registration_t *rp;
600 :
601 0 : rp = vl_api_client_index_to_registration (mp->client_index);
602 0 : if (rp == 0)
603 0 : return;
604 :
605 0 : entry_index = ntohl (mp->entry_index);
606 :
607 0 : if (~0 == entry_index)
608 : {
609 0 : pool_foreach (t, nm->nsh_entries)
610 : {
611 0 : send_nsh_entry_details (t, rp, mp->context);
612 : }
613 : }
614 : else
615 : {
616 0 : if (entry_index >= vec_len (nm->nsh_entries))
617 : {
618 0 : return;
619 : }
620 0 : t = &nm->nsh_entries[entry_index];
621 0 : send_nsh_entry_details (t, rp, mp->context);
622 : }
623 : }
624 :
625 : #include <nsh/nsh.api.c>
626 :
627 : /* Set up the API message handling tables */
628 : clib_error_t *
629 575 : nsh_api_init (vlib_main_t * vm, nsh_main_t * nm)
630 : {
631 : /* Add our API messages to the global name_crc hash table */
632 575 : nm->msg_id_base = setup_message_id_table ();
633 :
634 575 : return 0;
635 : }
636 :
637 : /*
638 : * fd.io coding-style-patch-verification: ON
639 : *
640 : * Local Variables:
641 : * eval: (c-set-style "gnu")
642 : * End:
643 : */
|