2 * sr_localsid.c: ipv6 segment routing Endpoint behaviors
4 * Copyright (c) 2016 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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @brief Processing of packets with a SRH
22 * CLI to define new Segment Routing End processing functions.
23 * Graph node to support such functions.
25 * Each function associates an SRv6 segment (IPv6 address) with an specific
26 * Segment Routing function.
30 #include <vlib/vlib.h>
31 #include <vnet/vnet.h>
32 #include <vnet/srv6/sr.h>
33 #include <vnet/ip/ip.h>
34 #include <vnet/srv6/sr_packet.h>
35 #include <vnet/ip/ip6_packet.h>
36 #include <vnet/fib/ip6_fib.h>
37 #include <vnet/dpo/dpo.h>
38 #include <vnet/adj/adj.h>
40 #include <vppinfra/error.h>
41 #include <vppinfra/elog.h>
44 * @brief Dynamically added SR localsid DPO type
46 static dpo_type_t sr_localsid_dpo_type;
47 static dpo_type_t sr_localsid_d_dpo_type;
48 static dpo_type_t sr_localsid_un_dpo_type;
49 static dpo_type_t sr_localsid_un_perf_dpo_type;
52 sr_localsid_key_create (sr_localsid_key_t * key, ip6_address_t * addr,
55 clib_memset (key, 0, sizeof (sr_localsid_key_t));
56 clib_memcpy (&key->address, addr, sizeof (ip6_address_t));
57 key->pref_len = pref_len;
61 * @brief SR localsid add/del
63 * Function to add or delete SR LocalSIDs.
65 * @param is_del Boolean of whether its a delete instruction
66 * @param localsid_addr IPv6 address of the localsid
67 * @param is_decap Boolean of whether decapsulation is allowed in this function
68 * @param behavior Type of behavior (function) for this localsid
69 * @param sw_if_index Only for L2/L3 xconnect. OIF. In VRF variant the fib_table.
70 * @param vlan_index Only for L2 xconnect. Outgoing VLAN tag.
71 * @param fib_table FIB table in which we should install the localsid entry
72 * @param nh_addr Next Hop IPv4/IPv6 address. Only for L2/L3 xconnect.
74 * @return 0 on success, error otherwise.
77 sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
78 u16 localsid_prefix_len, char end_psp, u8 behavior,
79 u32 sw_if_index, u32 vlan_index, u32 fib_table,
80 ip46_address_t * nh_addr, int usid_len, void *ls_plugin_mem)
82 ip6_sr_main_t *sm = &sr_main;
86 sr_localsid_fn_registration_t *plugin = 0;
87 sr_localsid_key_t key;
89 ip6_sr_localsid_t *ls = 0;
91 dpo_id_t dpo = DPO_INVALID;
93 /* Search for the item */
94 sr_localsid_key_create (&key, localsid_addr, localsid_prefix_len);
95 p = mhash_get (&sm->sr_localsids_index_hash, &key);
101 /* Retrieve localsid */
102 ls = pool_elt_at_index (sm->localsids, p[0]);
103 if (ls->behavior >= SR_BEHAVIOR_LAST)
105 plugin = pool_elt_at_index (sm->plugin_functions,
106 ls->behavior - SR_BEHAVIOR_LAST);
107 pref_length = plugin->prefix_length;
110 if (localsid_prefix_len != 0)
112 pref_length = localsid_prefix_len;
115 /* Delete FIB entry */
117 .fp_proto = FIB_PROTOCOL_IP6,
118 .fp_len = pref_length,
120 .ip6 = *localsid_addr,
124 fib_table_entry_delete (fib_table_find
125 (FIB_PROTOCOL_IP6, fib_table), &pfx,
128 /* In case it is a Xconnect iface remove the (OIF, NHOP) adj */
129 if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX6
130 || ls->behavior == SR_BEHAVIOR_DX4)
131 adj_unlock (ls->nh_adj);
133 if (ls->behavior >= SR_BEHAVIOR_LAST)
135 /* Callback plugin removal function */
136 rv = plugin->removal (ls);
139 /* Delete localsid registry */
140 pool_put (sm->localsids, ls);
141 mhash_unset (&sm->sr_localsids_index_hash, &key, NULL);
144 else /* create with function already existing; complain */
148 /* delete; localsid does not exist; complain */
152 if (behavior >= SR_BEHAVIOR_LAST)
154 sr_localsid_fn_registration_t *plugin = 0;
156 pool_elt_at_index (sm->plugin_functions, behavior - SR_BEHAVIOR_LAST);
157 pref_length = plugin->prefix_length;
160 if (localsid_prefix_len != 0)
162 pref_length = localsid_prefix_len;
165 /* Check whether there exists a FIB entry with such address */
167 .fp_proto = FIB_PROTOCOL_IP6,
168 .fp_len = pref_length,
171 pfx.fp_addr.as_u64[0] = localsid_addr->as_u64[0];
172 pfx.fp_addr.as_u64[1] = localsid_addr->as_u64[1];
173 pfx.fp_len = pref_length;
175 /* Lookup the FIB index associated to the table id provided */
176 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, fib_table);
180 /* Lookup the localsid in such FIB table */
181 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
182 if (FIB_NODE_INDEX_INVALID != fei)
183 return -4; //There is an entry for such address (the localsid addr)
185 /* Create a new localsid registry */
186 pool_get (sm->localsids, ls);
187 clib_memset (ls, 0, sizeof (*ls));
189 clib_memcpy (&ls->localsid, localsid_addr, sizeof (ip6_address_t));
190 ls->localsid_prefix_len = pref_length;
191 ls->end_psp = end_psp;
192 ls->behavior = behavior;
193 ls->nh_adj = (u32) ~ 0;
194 ls->fib_table = fib_table;
197 case SR_BEHAVIOR_END:
199 case SR_BEHAVIOR_END_UN:
200 case SR_BEHAVIOR_END_UN_PERF:
204 clib_memcpy (&ls->usid_block, localsid_addr,
205 sizeof (ip6_address_t));
207 usid_width = pref_length - usid_len;
208 ip6_address_mask_from_width (&ls->usid_block_mask, usid_width);
210 ls->usid_index = usid_width / 8;
211 ls->usid_len = usid_len / 8;
212 ls->usid_next_index = ls->usid_index + ls->usid_len;
213 ls->usid_next_len = 16 - ls->usid_next_index;
217 ls->sw_if_index = sw_if_index;
218 clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
221 ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
223 case SR_BEHAVIOR_DX4:
224 ls->sw_if_index = sw_if_index;
225 clib_memcpy (&ls->next_hop.ip4, &nh_addr->ip4, sizeof (ip4_address_t));
227 case SR_BEHAVIOR_DX6:
228 ls->sw_if_index = sw_if_index;
229 clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
231 case SR_BEHAVIOR_DT6:
232 ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
234 case SR_BEHAVIOR_DT4:
235 ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP4, sw_if_index);
237 case SR_BEHAVIOR_DX2:
238 ls->sw_if_index = sw_if_index;
239 ls->vlan_index = vlan_index;
243 /* Figure out the adjacency magic for Xconnect variants */
244 if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX4
245 || ls->behavior == SR_BEHAVIOR_DX6)
247 adj_index_t nh_adj_index = ADJ_INDEX_INVALID;
249 /* Retrieve the adjacency corresponding to the (OIF, next_hop) */
250 if (ls->behavior == SR_BEHAVIOR_DX6 || ls->behavior == SR_BEHAVIOR_X)
251 nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
252 nh_addr, sw_if_index);
254 else if (ls->behavior == SR_BEHAVIOR_DX4)
255 nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
256 nh_addr, sw_if_index);
258 /* Check for ADJ creation error. If so panic */
259 if (nh_adj_index == ADJ_INDEX_INVALID)
261 pool_put (sm->localsids, ls);
265 ls->nh_adj = nh_adj_index;
269 if (ls->behavior == SR_BEHAVIOR_END || ls->behavior == SR_BEHAVIOR_X
270 || ls->behavior == SR_BEHAVIOR_T)
271 dpo_set (&dpo, sr_localsid_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
272 else if (ls->behavior == SR_BEHAVIOR_END_UN)
273 dpo_set (&dpo, sr_localsid_un_dpo_type, DPO_PROTO_IP6,
275 else if (ls->behavior == SR_BEHAVIOR_END_UN_PERF)
276 dpo_set (&dpo, sr_localsid_un_perf_dpo_type, DPO_PROTO_IP6,
278 else if (ls->behavior > SR_BEHAVIOR_D_FIRST
279 && ls->behavior < SR_BEHAVIOR_LAST)
280 dpo_set (&dpo, sr_localsid_d_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
281 else if (ls->behavior >= SR_BEHAVIOR_LAST)
283 sr_localsid_fn_registration_t *plugin = 0;
284 plugin = pool_elt_at_index (sm->plugin_functions,
285 ls->behavior - SR_BEHAVIOR_LAST);
286 /* Copy the unformat memory result */
287 ls->plugin_mem = ls_plugin_mem;
288 /* Callback plugin creation function */
289 rv = plugin->creation (ls);
292 pool_put (sm->localsids, ls);
295 dpo_set (&dpo, plugin->dpo, DPO_PROTO_IP6, ls - sm->localsids);
298 /* Set hash key for searching localsid by address */
299 mhash_set (&sm->sr_localsids_index_hash, &key, ls - sm->localsids, NULL);
301 fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR,
302 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
305 /* Set counter to zero */
306 vlib_validate_combined_counter (&(sm->sr_ls_valid_counters),
308 vlib_validate_combined_counter (&(sm->sr_ls_invalid_counters),
311 vlib_zero_combined_counter (&(sm->sr_ls_valid_counters),
313 vlib_zero_combined_counter (&(sm->sr_ls_invalid_counters),
320 * @brief SR LocalSID CLI function.
322 * @see sr_cli_localsid
324 static clib_error_t *
325 sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
326 vlib_cli_command_t * cmd)
328 vnet_main_t *vnm = vnet_get_main ();
329 ip6_sr_main_t *sm = &sr_main;
330 u32 sw_if_index = (u32) ~ 0, vlan_index = (u32) ~ 0, fib_index = 0;
334 ip6_address_t resulting_address;
335 ip46_address_t next_hop;
336 char address_set = 0;
338 void *ls_plugin_mem = 0;
343 clib_memset (&resulting_address, 0, sizeof (ip6_address_t));
344 ip46_address_reset (&next_hop);
346 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
348 if (unformat (input, "del"))
350 else if (!address_set
351 && unformat (input, "prefix %U/%u", unformat_ip6_address,
352 &resulting_address, &prefix_len))
354 else if (!address_set
355 && unformat (input, "address %U", unformat_ip6_address,
358 else if (!address_set
359 && unformat (input, "addr %U", unformat_ip6_address,
362 else if (unformat (input, "fib-table %u", &fib_index));
363 else if (vlan_index == (u32) ~ 0
364 && unformat (input, "vlan %u", &vlan_index));
365 else if (!behavior && unformat (input, "behavior"))
367 if (unformat (input, "end.x %U %U",
368 unformat_vnet_sw_interface, vnm, &sw_if_index,
369 unformat_ip6_address, &next_hop.ip6))
370 behavior = SR_BEHAVIOR_X;
371 else if (unformat (input, "end.t %u", &sw_if_index))
372 behavior = SR_BEHAVIOR_T;
373 else if (unformat (input, "end.dx6 %U %U",
374 unformat_vnet_sw_interface, vnm, &sw_if_index,
375 unformat_ip6_address, &next_hop.ip6))
376 behavior = SR_BEHAVIOR_DX6;
377 else if (unformat (input, "end.dx4 %U %U",
378 unformat_vnet_sw_interface, vnm, &sw_if_index,
379 unformat_ip4_address, &next_hop.ip4))
380 behavior = SR_BEHAVIOR_DX4;
381 else if (unformat (input, "end.dx2 %U",
382 unformat_vnet_sw_interface, vnm, &sw_if_index))
383 behavior = SR_BEHAVIOR_DX2;
384 else if (unformat (input, "end.dt6 %u", &sw_if_index))
385 behavior = SR_BEHAVIOR_DT6;
386 else if (unformat (input, "end.dt4 %u", &sw_if_index))
387 behavior = SR_BEHAVIOR_DT4;
388 else if (unformat (input, "un %u", &usid_size))
389 behavior = SR_BEHAVIOR_END_UN_PERF;
390 else if (unformat (input, "un.flex %u", &usid_size))
391 behavior = SR_BEHAVIOR_END_UN;
394 /* Loop over all the plugin behavior format functions */
395 sr_localsid_fn_registration_t *plugin = 0, **vec_plugins = 0;
396 sr_localsid_fn_registration_t **plugin_it = 0;
398 /* Create a vector out of the plugin pool as recommended */
400 pool_foreach (plugin, sm->plugin_functions)
402 vec_add1 (vec_plugins, plugin);
406 vec_foreach (plugin_it, vec_plugins)
409 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
411 behavior = (*plugin_it)->sr_localsid_function_number;
419 if (unformat (input, "end"))
420 behavior = SR_BEHAVIOR_END;
425 else if (!end_psp && unformat (input, "psp"))
431 if (!behavior && end_psp)
432 behavior = SR_BEHAVIOR_END;
436 if (prefix_len < usid_size)
437 return clib_error_return (0,
438 "Error: Prefix length must be greater"
439 " than uSID length.");
441 if (usid_size != 16 && usid_size != 32)
442 return clib_error_return (0,
443 "Error: Invalid uSID length (16 or 32).");
445 if ((prefix_len - usid_size) & 0x7)
446 return clib_error_return (0,
447 "Error: Prefix Length must be multiple of 8.");
451 return clib_error_return (0,
452 "Error: SRv6 LocalSID address is mandatory.");
453 if (!is_del && !behavior)
454 return clib_error_return (0,
455 "Error: SRv6 LocalSID behavior is mandatory.");
456 if (vlan_index != (u32) ~ 0)
457 return clib_error_return (0,
458 "Error: SRv6 End.DX2 with rewrite VLAN tag not supported by now.");
459 if (end_psp && !(behavior == SR_BEHAVIOR_END || behavior == SR_BEHAVIOR_X))
460 return clib_error_return (0,
461 "Error: SRv6 PSP only compatible with End and End.X");
464 sr_cli_localsid (is_del, &resulting_address, prefix_len, end_psp,
465 behavior, sw_if_index, vlan_index, fib_index, &next_hop,
466 usid_size, ls_plugin_mem);
468 if (behavior == SR_BEHAVIOR_END_UN_PERF)
473 perf_len = prefix_len + usid_size;
474 rv = sr_cli_localsid (is_del, &resulting_address, perf_len, end_psp,
475 SR_BEHAVIOR_END, sw_if_index, vlan_index,
476 fib_index, &next_hop, 0, ls_plugin_mem);
487 return clib_error_return (0,
488 "Identical localsid already exists. Requested localsid not created.");
490 return clib_error_return (0,
491 "The requested localsid could not be deleted. SR localsid not found");
493 return clib_error_return (0, "FIB table %u does not exist", fib_index);
495 return clib_error_return (0, "There is already one FIB entry for the"
496 "requested localsid non segment routing related");
498 return clib_error_return (0,
499 "Could not create ARP/ND entry for such next_hop. Internal error.");
501 return clib_error_return (0,
502 "Error on the plugin based localsid creation.");
504 return clib_error_return (0, "BUG: sr localsid returns %d", rv);
510 VLIB_CLI_COMMAND (sr_localsid_command, static) = {
511 .path = "sr localsid",
512 .short_help = "sr localsid (del) address XX:XX::YY:YY"
513 "(fib-table 8) behavior STRING",
515 "Create SR LocalSID and binds it to a particular behavior\n"
517 "\tlocalSID IPv6_addr(128b) LocalSID IPv6 address\n"
518 "\t(fib-table X) Optional. VRF where to install SRv6 localsid\n"
519 "\tbehavior STRING Specifies the behavior\n"
521 "\tEnd\t-> Endpoint.\n"
522 "\tEnd.uN\t-> Endpoint with uSID.\n"
523 "\tEnd.X\t-> Endpoint with decapsulation and Layer-3 cross-connect.\n"
524 "\t\tParameters: '<iface> <ip6_next_hop>'\n"
525 "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
526 "\t\tParameters: '<iface>'\n"
527 "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
528 "\t\tParameters: '<iface> <ip6_next_hop>'\n"
529 "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
530 "\t\tParameters: '<iface> <ip4_next_hop>'\n"
531 "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
532 "\t\tParameters: '<ip6_fib_table>'\n"
533 "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
534 "\t\tParameters: '<ip4_fib_table>'\n",
535 .function = sr_cli_localsid_command_fn,
540 * @brief CLI function to 'show' all SR LocalSIDs on console.
542 static clib_error_t *
543 show_sr_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
544 vlib_cli_command_t * cmd)
546 vnet_main_t *vnm = vnet_get_main ();
547 ip6_sr_main_t *sm = &sr_main;
548 ip6_sr_localsid_t **localsid_list = 0;
549 ip6_sr_localsid_t *ls;
552 vlib_cli_output (vm, "SRv6 - My LocalSID Table:");
553 vlib_cli_output (vm, "=========================");
555 pool_foreach (ls, sm->localsids) { vec_add1 (localsid_list, ls); }
557 for (i = 0; i < vec_len (localsid_list); i++)
559 ls = localsid_list[i];
560 switch (ls->behavior)
562 case SR_BEHAVIOR_END:
563 vlib_cli_output (vm, "\tAddress: \t%U\n\tBehavior: \tEnd",
564 format_ip6_address, &ls->localsid);
566 case SR_BEHAVIOR_END_UN:
568 "\tAddress: \t%U\n\tBehavior: \tEnd (flex) [uSID:\t%U/%d, length: %d]",
569 format_ip6_address, &ls->localsid,
570 format_ip6_address, &ls->usid_block,
571 ls->usid_index * 8, ls->usid_len * 8);
573 case SR_BEHAVIOR_END_UN_PERF:
575 "\tAddress: \t%U\n\tBehavior: \tEnd [uSID:\t%U/%d, length: %d]",
576 format_ip6_address, &ls->localsid,
577 format_ip6_address, &ls->usid_block,
578 ls->usid_index * 8, ls->usid_len * 8);
582 "\tAddress: \t%U/%u\n\tBehavior: \tX (Endpoint with Layer-3 cross-connect)"
583 "\n\tIface: \t%U\n\tNext hop: \t%U",
584 format_ip6_address, &ls->localsid,
585 ls->localsid_prefix_len,
586 format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
587 format_ip6_address, &ls->next_hop.ip6);
591 "\tAddress: \t%U/%u\n\tBehavior: \tT (Endpoint with specific IPv6 table lookup)"
593 format_ip6_address, &ls->localsid,
594 ls->localsid_prefix_len,
595 fib_table_get_table_id (ls->vrf_index,
598 case SR_BEHAVIOR_DX4:
600 "\tAddress: \t%U/%u\n\tBehavior: \tDX4 (Endpoint with decapsulation and IPv4 cross-connect)"
601 "\n\tIface: \t%U\n\tNext hop: \t%U",
602 format_ip6_address, &ls->localsid,
603 ls->localsid_prefix_len,
604 format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
605 format_ip4_address, &ls->next_hop.ip4);
607 case SR_BEHAVIOR_DX6:
609 "\tAddress: \t%U/%u\n\tBehavior: \tDX6 (Endpoint with decapsulation and IPv6 cross-connect)"
610 "\n\tIface: \t%U\n\tNext hop: \t%U",
611 format_ip6_address, &ls->localsid,
612 ls->localsid_prefix_len,
613 format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
614 format_ip6_address, &ls->next_hop.ip6);
616 case SR_BEHAVIOR_DX2:
617 if (ls->vlan_index == (u32) ~ 0)
619 "\tAddress: \t%U/%u\n\tBehavior: \tDX2 (Endpoint with decapulation and Layer-2 cross-connect)"
620 "\n\tIface: \t%U", format_ip6_address,
621 &ls->localsid, ls->localsid_prefix_len,
622 format_vnet_sw_if_index_name, vnm,
626 "Unsupported yet. (DX2 with egress VLAN rewrite)");
628 case SR_BEHAVIOR_DT6:
630 "\tAddress: \t%U/%u\n\tBehavior: \tDT6 (Endpoint with decapsulation and specific IPv6 table lookup)"
631 "\n\tTable: %u", format_ip6_address, &ls->localsid,
632 ls->localsid_prefix_len,
633 fib_table_get_table_id (ls->vrf_index,
636 case SR_BEHAVIOR_DT4:
638 "\tAddress: \t%U/%u\n\tBehavior: \tDT4 (Endpoint with decapsulation and specific IPv4 table lookup)"
639 "\n\tTable: \t%u", format_ip6_address,
640 &ls->localsid, ls->localsid_prefix_len,
641 fib_table_get_table_id (ls->vrf_index,
645 if (ls->behavior >= SR_BEHAVIOR_LAST)
647 sr_localsid_fn_registration_t *plugin =
648 pool_elt_at_index (sm->plugin_functions,
649 ls->behavior - SR_BEHAVIOR_LAST);
651 vlib_cli_output (vm, "\tAddress: \t%U/%u\n"
652 "\tBehavior: \t%s (%s)\n\t%U",
653 format_ip6_address, &ls->localsid,
654 ls->localsid_prefix_len, plugin->keyword_str,
655 plugin->def_str, plugin->ls_format,
659 //Should never get here...
660 vlib_cli_output (vm, "Internal error");
664 vlib_cli_output (vm, "\tPSP: \tTrue\n");
667 vlib_counter_t valid, invalid;
668 vlib_get_combined_counter (&(sm->sr_ls_valid_counters), i, &valid);
669 vlib_get_combined_counter (&(sm->sr_ls_invalid_counters), i, &invalid);
670 vlib_cli_output (vm, "\tGood traffic: \t[%Ld packets : %Ld bytes]\n",
671 valid.packets, valid.bytes);
672 vlib_cli_output (vm, "\tBad traffic: \t[%Ld packets : %Ld bytes]\n",
673 invalid.packets, invalid.bytes);
674 vlib_cli_output (vm, "--------------------");
680 VLIB_CLI_COMMAND (show_sr_localsid_command, static) = {
681 .path = "show sr localsids",
682 .short_help = "show sr localsids",
683 .function = show_sr_localsid_command_fn,
688 * @brief Function to 'clear' ALL SR localsid counters
690 static clib_error_t *
691 clear_sr_localsid_counters_command_fn (vlib_main_t * vm,
692 unformat_input_t * input,
693 vlib_cli_command_t * cmd)
695 ip6_sr_main_t *sm = &sr_main;
697 vlib_clear_combined_counters (&(sm->sr_ls_valid_counters));
698 vlib_clear_combined_counters (&(sm->sr_ls_invalid_counters));
704 VLIB_CLI_COMMAND (clear_sr_localsid_counters_command, static) = {
705 .path = "clear sr localsid-counters",
706 .short_help = "clear sr localsid-counters",
707 .function = clear_sr_localsid_counters_command_fn,
711 /************************ SR LocalSID graphs node ****************************/
713 * @brief SR localsid node trace
717 ip6_address_t localsid;
722 } sr_localsid_trace_t;
724 #define foreach_sr_localsid_error \
725 _(NO_INNER_HEADER, "(SR-Error) No inner IP header") \
726 _(NO_MORE_SEGMENTS, "(SR-Error) No more segments") \
727 _(NO_SRH, "(SR-Error) No SR header") \
728 _(NO_PSP, "(SR-Error) PSP Not available (segments left > 0)") \
729 _(NOT_LS, "(SR-Error) Decaps not available (segments left > 0)") \
730 _(L2, "(SR-Error) SRv6 decapsulated a L2 frame without dest")
734 #define _(sym,str) SR_LOCALSID_ERROR_##sym,
735 foreach_sr_localsid_error
738 } sr_localsid_error_t;
740 static char *sr_localsid_error_strings[] = {
741 #define _(sym,string) string,
742 foreach_sr_localsid_error
746 #define foreach_sr_localsid_next \
747 _(ERROR, "error-drop") \
748 _(IP6_LOOKUP, "ip6-lookup") \
749 _(IP4_LOOKUP, "ip4-lookup") \
750 _(IP6_REWRITE, "ip6-rewrite") \
751 _(IP4_REWRITE, "ip4-rewrite") \
752 _(INTERFACE_OUTPUT, "interface-output")
756 #define _(s,n) SR_LOCALSID_NEXT_##s,
757 foreach_sr_localsid_next
760 } sr_localsid_next_t;
763 * @brief SR LocalSID graph node trace function
768 format_sr_localsid_trace (u8 * s, va_list * args)
770 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
771 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
772 sr_localsid_trace_t *t = va_arg (*args, sr_localsid_trace_t *);
775 format (s, "SR-LOCALSID:\n\tLocalsid: %U\n", format_ip6_address,
779 case SR_BEHAVIOR_END:
780 s = format (s, "\tBehavior: End\n");
782 case SR_BEHAVIOR_END_UN:
783 s = format (s, "\tBehavior: End.uN (flex)\n");
785 case SR_BEHAVIOR_END_UN_PERF:
786 s = format (s, "\tBehavior: End.uN\n");
788 case SR_BEHAVIOR_DX6:
789 s = format (s, "\tBehavior: Decapsulation with IPv6 L3 xconnect\n");
791 case SR_BEHAVIOR_DX4:
792 s = format (s, "\tBehavior: Decapsulation with IPv4 L3 xconnect\n");
795 s = format (s, "\tBehavior: IPv6 L3 xconnect\n");
798 s = format (s, "\tBehavior: IPv6 specific table lookup\n");
800 case SR_BEHAVIOR_DT6:
801 s = format (s, "\tBehavior: Decapsulation with IPv6 Table lookup\n");
803 case SR_BEHAVIOR_DT4:
804 s = format (s, "\tBehavior: Decapsulation with IPv4 Table lookup\n");
806 case SR_BEHAVIOR_DX2:
807 s = format (s, "\tBehavior: Decapsulation with L2 xconnect\n");
810 s = format (s, "\tBehavior: defined in plugin\n"); //TODO
813 if (t->num_segments != 0xFF)
815 if (t->num_segments > 0)
817 s = format (s, "\tSegments left: %d\n", t->segments_left);
818 s = format (s, "\tSID list: [in ietf order]");
820 for (i = 0; i < t->num_segments; i++)
822 s = format (s, "\n\t-> %U", format_ip6_address,
823 (ip6_address_t *) & t->sr[i *
824 sizeof (ip6_address_t)]);
832 * @brief Function doing End processing.
834 static_always_inline void
835 end_srh_processing (vlib_node_runtime_t * node,
838 ip6_sr_header_t * sr0,
839 ip6_sr_localsid_t * ls0,
840 u32 * next0, u8 psp, ip6_ext_header_t * prev0)
842 ip6_address_t *new_dst0;
844 if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
846 if (sr0->segments_left == 1 && psp)
849 u64 *copy_dst0, *copy_src0;
850 u32 copy_len_u64s0 = 0;
852 ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
853 ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
855 /* Remove the SRH taking care of the rest of IPv6 ext header */
857 prev0->next_hdr = sr0->protocol;
859 ip0->protocol = sr0->protocol;
861 sr_len = ip6_ext_header_len (sr0);
862 vlib_buffer_advance (b0, sr_len);
863 new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
864 ip0->payload_length = clib_host_to_net_u16 (new_l0);
865 copy_src0 = (u64 *) ip0;
866 copy_dst0 = copy_src0 + (sr0->length + 1);
867 /* number of 8 octet units to copy
868 * By default in absence of extension headers it is equal to length of ip6 header
869 * With extension headers it number of 8 octet units of ext headers preceding
873 (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
874 copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
875 copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
876 copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
877 copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
878 copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
881 for (i = copy_len_u64s0 - 1; i >= 0; i--)
883 copy_dst0[i] = copy_src0[i];
886 if (ls0->behavior == SR_BEHAVIOR_X)
888 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
889 *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
891 else if (ls0->behavior == SR_BEHAVIOR_T)
893 vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
896 else if (PREDICT_TRUE (sr0->segments_left > 0))
898 sr0->segments_left -= 1;
899 new_dst0 = (ip6_address_t *) (sr0->segments);
900 new_dst0 += sr0->segments_left;
901 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
902 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
904 if (ls0->behavior == SR_BEHAVIOR_X)
906 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
907 *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
909 else if (ls0->behavior == SR_BEHAVIOR_T)
911 vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
916 *next0 = SR_LOCALSID_NEXT_ERROR;
917 b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
922 /* Error. Routing header of type != SR */
923 *next0 = SR_LOCALSID_NEXT_ERROR;
924 b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
929 * @brief Function doing End uN processing.
931 static_always_inline void
932 end_un_srh_processing (vlib_node_runtime_t * node,
935 ip6_sr_header_t * sr0,
936 ip6_sr_localsid_t * ls0,
937 u32 * next0, u8 psp, ip6_ext_header_t * prev0)
939 ip6_address_t *new_dst0;
940 bool next_usid = false;
945 usid_len = ls0->usid_len;
946 next_usid_index = ls0->usid_next_index;
949 for (index = 0; index < usid_len; index++)
951 if (ip0->dst_address.as_u8[next_usid_index + index] != 0)
958 if (PREDICT_TRUE (next_usid))
962 index = ls0->usid_index;
964 /* advance next usid */
965 for (offset = 0; offset < ls0->usid_next_len; offset++)
967 ip0->dst_address.as_u8[index + offset] =
968 ip0->dst_address.as_u8[next_usid_index + offset];
971 for (index = 16 - usid_len; index < 16; index++)
973 ip0->dst_address.as_u8[index] = 0;
979 if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
981 if (sr0->segments_left == 1 && psp)
984 u64 *copy_dst0, *copy_src0;
985 u32 copy_len_u64s0 = 0;
987 ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
988 ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
990 /* Remove the SRH taking care of the rest of IPv6 ext header */
992 prev0->next_hdr = sr0->protocol;
994 ip0->protocol = sr0->protocol;
996 sr_len = ip6_ext_header_len (sr0);
997 vlib_buffer_advance (b0, sr_len);
998 new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
999 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1000 copy_src0 = (u64 *) ip0;
1001 copy_dst0 = copy_src0 + (sr0->length + 1);
1002 /* number of 8 octet units to copy
1003 * By default in absence of extension headers it is equal to length of ip6 header
1004 * With extension headers it number of 8 octet units of ext headers preceding
1008 (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
1009 copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
1010 copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
1011 copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
1012 copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
1013 copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
1016 for (i = copy_len_u64s0 - 1; i >= 0; i--)
1018 copy_dst0[i] = copy_src0[i];
1021 else if (PREDICT_TRUE (sr0->segments_left > 0))
1023 sr0->segments_left -= 1;
1024 new_dst0 = (ip6_address_t *) (sr0->segments);
1025 new_dst0 += sr0->segments_left;
1026 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1027 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1031 *next0 = SR_LOCALSID_NEXT_ERROR;
1032 b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
1037 /* Error. Routing header of type != SR */
1038 *next0 = SR_LOCALSID_NEXT_ERROR;
1039 b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
1043 static_always_inline void
1044 end_un_processing (ip6_header_t * ip0, ip6_sr_localsid_t * ls0)
1051 index = ls0->usid_index;
1052 next_usid_index = ls0->usid_next_index;
1054 /* advance next usid */
1055 for (offset = 0; offset < ls0->usid_next_len; offset++)
1057 ip0->dst_address.as_u8[index + offset] =
1058 ip0->dst_address.as_u8[next_usid_index + offset];
1061 for (index = 16 - ls0->usid_len; index < 16; index++)
1063 ip0->dst_address.as_u8[index] = 0;
1070 * @brief Function doing SRH processing for D* variants
1072 static_always_inline void
1073 end_decaps_srh_processing (vlib_node_runtime_t * node,
1076 ip6_sr_header_t * sr0,
1077 ip6_sr_localsid_t * ls0, u32 * next0)
1079 /* Compute the size of the IPv6 header with all Ext. headers */
1081 ip6_ext_header_t *next_ext_header;
1084 next_proto = ip0->protocol;
1085 next_ext_header = (void *) (ip0 + 1);
1086 total_size = sizeof (ip6_header_t);
1087 while (ip6_ext_hdr (next_proto))
1089 total_size += ip6_ext_header_len (next_ext_header);
1090 next_proto = next_ext_header->next_hdr;
1091 next_ext_header = ip6_ext_next_header (next_ext_header);
1094 /* Ensure this is the last segment. Otherwise drop. */
1095 if (sr0 && sr0->segments_left != 0)
1097 *next0 = SR_LOCALSID_NEXT_ERROR;
1098 b0->error = node->errors[SR_LOCALSID_ERROR_NOT_LS];
1104 case IP_PROTOCOL_IPV6:
1105 /* Encap-End IPv6. Pop outer IPv6 header. */
1106 if (ls0->behavior == SR_BEHAVIOR_DX6)
1108 vlib_buffer_advance (b0, total_size);
1109 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1110 *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
1113 else if (ls0->behavior == SR_BEHAVIOR_DT6)
1115 vlib_buffer_advance (b0, total_size);
1116 vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1120 case IP_PROTOCOL_IP_IN_IP:
1121 /* Encap-End IPv4. Pop outer IPv6 header */
1122 if (ls0->behavior == SR_BEHAVIOR_DX4)
1124 vlib_buffer_advance (b0, total_size);
1125 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1126 *next0 = SR_LOCALSID_NEXT_IP4_REWRITE;
1129 else if (ls0->behavior == SR_BEHAVIOR_DT4)
1131 vlib_buffer_advance (b0, total_size);
1132 vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1133 *next0 = SR_LOCALSID_NEXT_IP4_LOOKUP;
1137 case IP_PROTOCOL_IP6_ETHERNET:
1139 if (ls0->behavior == SR_BEHAVIOR_DX2)
1141 vlib_buffer_advance (b0, total_size);
1142 vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->sw_if_index;
1143 *next0 = SR_LOCALSID_NEXT_INTERFACE_OUTPUT;
1148 *next0 = SR_LOCALSID_NEXT_ERROR;
1149 b0->error = node->errors[SR_LOCALSID_ERROR_NO_INNER_HEADER];
1154 * @brief SR LocalSID graph node. Supports all default SR Endpoint variants with decaps
1157 sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1158 vlib_frame_t * from_frame)
1160 u32 n_left_from, next_index, *from, *to_next;
1161 ip6_sr_main_t *sm = &sr_main;
1162 from = vlib_frame_vector_args (from_frame);
1163 n_left_from = from_frame->n_vectors;
1164 next_index = node->cached_next_index;
1165 u32 thread_index = vm->thread_index;
1167 while (n_left_from > 0)
1170 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1173 while (n_left_from >= 8 && n_left_to_next >= 4)
1175 u32 bi0, bi1, bi2, bi3;
1176 vlib_buffer_t *b0, *b1, *b2, *b3;
1177 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1178 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1179 u32 next0, next1, next2, next3;
1180 next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1181 ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1183 /* Prefetch next iteration. */
1185 vlib_buffer_t *p4, *p5, *p6, *p7;
1187 p4 = vlib_get_buffer (vm, from[4]);
1188 p5 = vlib_get_buffer (vm, from[5]);
1189 p6 = vlib_get_buffer (vm, from[6]);
1190 p7 = vlib_get_buffer (vm, from[7]);
1192 /* Prefetch the buffer header and packet for the N+4 loop iteration */
1193 vlib_prefetch_buffer_header (p4, LOAD);
1194 vlib_prefetch_buffer_header (p5, LOAD);
1195 vlib_prefetch_buffer_header (p6, LOAD);
1196 vlib_prefetch_buffer_header (p7, LOAD);
1198 clib_prefetch_store (p4->data);
1199 clib_prefetch_store (p5->data);
1200 clib_prefetch_store (p6->data);
1201 clib_prefetch_store (p7->data);
1204 to_next[0] = bi0 = from[0];
1205 to_next[1] = bi1 = from[1];
1206 to_next[2] = bi2 = from[2];
1207 to_next[3] = bi3 = from[3];
1211 n_left_to_next -= 4;
1213 b0 = vlib_get_buffer (vm, bi0);
1214 b1 = vlib_get_buffer (vm, bi1);
1215 b2 = vlib_get_buffer (vm, bi2);
1216 b3 = vlib_get_buffer (vm, bi3);
1219 pool_elt_at_index (sm->localsids,
1220 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1222 pool_elt_at_index (sm->localsids,
1223 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1225 pool_elt_at_index (sm->localsids,
1226 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1228 pool_elt_at_index (sm->localsids,
1229 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1231 ip0 = vlib_buffer_get_current (b0);
1232 ip1 = vlib_buffer_get_current (b1);
1233 ip2 = vlib_buffer_get_current (b2);
1234 ip3 = vlib_buffer_get_current (b3);
1237 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1239 ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, NULL);
1241 ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, NULL);
1243 ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, NULL);
1245 end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1246 end_decaps_srh_processing (node, b1, ip1, sr1, ls1, &next1);
1247 end_decaps_srh_processing (node, b2, ip2, sr2, ls2, &next2);
1248 end_decaps_srh_processing (node, b3, ip3, sr3, ls3, &next3);
1250 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1252 sr_localsid_trace_t *tr =
1253 vlib_add_trace (vm, node, b0, sizeof (*tr));
1254 tr->num_segments = 0;
1255 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1256 sizeof (tr->localsid.as_u8));
1257 tr->behavior = ls0->behavior;
1258 if (ip0 == vlib_buffer_get_current (b0))
1260 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1261 && sr0->type == ROUTING_HEADER_TYPE_SR)
1263 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1265 sr0->length * 8 / sizeof (ip6_address_t);
1266 tr->segments_left = sr0->segments_left;
1270 tr->num_segments = 0xFF;
1273 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1275 sr_localsid_trace_t *tr =
1276 vlib_add_trace (vm, node, b1, sizeof (*tr));
1277 tr->num_segments = 0;
1278 clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1279 sizeof (tr->localsid.as_u8));
1280 tr->behavior = ls1->behavior;
1281 if (ip1 == vlib_buffer_get_current (b1))
1283 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1284 && sr1->type == ROUTING_HEADER_TYPE_SR)
1286 clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1288 sr1->length * 8 / sizeof (ip6_address_t);
1289 tr->segments_left = sr1->segments_left;
1293 tr->num_segments = 0xFF;
1296 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1298 sr_localsid_trace_t *tr =
1299 vlib_add_trace (vm, node, b2, sizeof (*tr));
1300 tr->num_segments = 0;
1301 clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1302 sizeof (tr->localsid.as_u8));
1303 tr->behavior = ls2->behavior;
1304 if (ip2 == vlib_buffer_get_current (b2))
1306 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1307 && sr2->type == ROUTING_HEADER_TYPE_SR)
1309 clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1311 sr2->length * 8 / sizeof (ip6_address_t);
1312 tr->segments_left = sr2->segments_left;
1316 tr->num_segments = 0xFF;
1319 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1321 sr_localsid_trace_t *tr =
1322 vlib_add_trace (vm, node, b3, sizeof (*tr));
1323 tr->num_segments = 0;
1324 clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1325 sizeof (tr->localsid.as_u8));
1326 tr->behavior = ls3->behavior;
1327 if (ip3 == vlib_buffer_get_current (b3))
1329 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1330 && sr3->type == ROUTING_HEADER_TYPE_SR)
1332 clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1334 sr3->length * 8 / sizeof (ip6_address_t);
1335 tr->segments_left = sr3->segments_left;
1339 tr->num_segments = 0xFF;
1342 vlib_increment_combined_counter
1344 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1345 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1346 1, vlib_buffer_length_in_chain (vm, b0));
1348 vlib_increment_combined_counter
1350 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1351 &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1352 1, vlib_buffer_length_in_chain (vm, b1));
1354 vlib_increment_combined_counter
1356 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1357 &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1358 1, vlib_buffer_length_in_chain (vm, b2));
1360 vlib_increment_combined_counter
1362 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1363 &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1364 1, vlib_buffer_length_in_chain (vm, b3));
1366 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1367 n_left_to_next, bi0, bi1, bi2, bi3,
1368 next0, next1, next2, next3);
1371 /* Single loop for potentially the last three packets */
1372 while (n_left_from > 0 && n_left_to_next > 0)
1377 ip6_sr_header_t *sr0;
1378 u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1379 ip6_sr_localsid_t *ls0;
1386 n_left_to_next -= 1;
1388 b0 = vlib_get_buffer (vm, bi0);
1389 ip0 = vlib_buffer_get_current (b0);
1391 /* Lookup the SR End behavior based on IP DA (adj) */
1393 pool_elt_at_index (sm->localsids,
1394 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1396 /* Find SRH as well as previous header */
1398 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1400 /* SRH processing and End variants */
1401 end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1403 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1405 sr_localsid_trace_t *tr =
1406 vlib_add_trace (vm, node, b0, sizeof (*tr));
1407 tr->num_segments = 0;
1408 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1409 sizeof (tr->localsid.as_u8));
1410 tr->behavior = ls0->behavior;
1411 if (ip0 == vlib_buffer_get_current (b0))
1413 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1414 && sr0->type == ROUTING_HEADER_TYPE_SR)
1416 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1418 sr0->length * 8 / sizeof (ip6_address_t);
1419 tr->segments_left = sr0->segments_left;
1423 tr->num_segments = 0xFF;
1426 /* Increase the counters */
1427 vlib_increment_combined_counter
1429 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1430 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1431 1, vlib_buffer_length_in_chain (vm, b0));
1433 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1434 n_left_to_next, bi0, next0);
1436 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1438 return from_frame->n_vectors;
1442 VLIB_REGISTER_NODE (sr_localsid_d_node) = {
1443 .function = sr_localsid_d_fn,
1444 .name = "sr-localsid-d",
1445 .vector_size = sizeof (u32),
1446 .format_trace = format_sr_localsid_trace,
1447 .type = VLIB_NODE_TYPE_INTERNAL,
1448 .n_errors = SR_LOCALSID_N_ERROR,
1449 .error_strings = sr_localsid_error_strings,
1450 .n_next_nodes = SR_LOCALSID_N_NEXT,
1452 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1453 foreach_sr_localsid_next
1460 * @brief SR LocalSID graph node. Supports all default SR Endpoint without decaps
1463 sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1464 vlib_frame_t * from_frame)
1466 u32 n_left_from, next_index, *from, *to_next;
1467 ip6_sr_main_t *sm = &sr_main;
1468 from = vlib_frame_vector_args (from_frame);
1469 n_left_from = from_frame->n_vectors;
1470 next_index = node->cached_next_index;
1471 u32 thread_index = vm->thread_index;
1473 while (n_left_from > 0)
1476 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1479 while (n_left_from >= 8 && n_left_to_next >= 4)
1481 u32 bi0, bi1, bi2, bi3;
1482 vlib_buffer_t *b0, *b1, *b2, *b3;
1483 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1484 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1485 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1486 u32 next0, next1, next2, next3;
1487 next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1488 ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1490 /* Prefetch next iteration. */
1492 vlib_buffer_t *p4, *p5, *p6, *p7;
1494 p4 = vlib_get_buffer (vm, from[4]);
1495 p5 = vlib_get_buffer (vm, from[5]);
1496 p6 = vlib_get_buffer (vm, from[6]);
1497 p7 = vlib_get_buffer (vm, from[7]);
1499 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1500 vlib_prefetch_buffer_header (p4, LOAD);
1501 vlib_prefetch_buffer_header (p5, LOAD);
1502 vlib_prefetch_buffer_header (p6, LOAD);
1503 vlib_prefetch_buffer_header (p7, LOAD);
1505 clib_prefetch_store (p4->data);
1506 clib_prefetch_store (p5->data);
1507 clib_prefetch_store (p6->data);
1508 clib_prefetch_store (p7->data);
1511 to_next[0] = bi0 = from[0];
1512 to_next[1] = bi1 = from[1];
1513 to_next[2] = bi2 = from[2];
1514 to_next[3] = bi3 = from[3];
1518 n_left_to_next -= 4;
1520 b0 = vlib_get_buffer (vm, bi0);
1521 b1 = vlib_get_buffer (vm, bi1);
1522 b2 = vlib_get_buffer (vm, bi2);
1523 b3 = vlib_get_buffer (vm, bi3);
1525 ip0 = vlib_buffer_get_current (b0);
1526 ip1 = vlib_buffer_get_current (b1);
1527 ip2 = vlib_buffer_get_current (b2);
1528 ip3 = vlib_buffer_get_current (b3);
1531 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1533 ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1535 ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1537 ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1540 pool_elt_at_index (sm->localsids,
1541 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1543 pool_elt_at_index (sm->localsids,
1544 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1546 pool_elt_at_index (sm->localsids,
1547 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1549 pool_elt_at_index (sm->localsids,
1550 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1552 end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1554 end_srh_processing (node, b1, ip1, sr1, ls1, &next1, ls1->end_psp,
1556 end_srh_processing (node, b2, ip2, sr2, ls2, &next2, ls2->end_psp,
1558 end_srh_processing (node, b3, ip3, sr3, ls3, &next3, ls3->end_psp,
1561 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1563 sr_localsid_trace_t *tr =
1564 vlib_add_trace (vm, node, b0, sizeof (*tr));
1565 tr->num_segments = 0;
1566 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1567 sizeof (tr->localsid.as_u8));
1568 tr->behavior = ls0->behavior;
1569 if (ip0 == vlib_buffer_get_current (b0))
1571 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1572 && sr0->type == ROUTING_HEADER_TYPE_SR)
1574 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1576 sr0->length * 8 / sizeof (ip6_address_t);
1577 tr->segments_left = sr0->segments_left;
1581 tr->num_segments = 0xFF;
1584 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1586 sr_localsid_trace_t *tr =
1587 vlib_add_trace (vm, node, b1, sizeof (*tr));
1588 tr->num_segments = 0;
1589 clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1590 sizeof (tr->localsid.as_u8));
1591 tr->behavior = ls1->behavior;
1592 if (ip1 == vlib_buffer_get_current (b1))
1594 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1595 && sr1->type == ROUTING_HEADER_TYPE_SR)
1597 clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1599 sr1->length * 8 / sizeof (ip6_address_t);
1600 tr->segments_left = sr1->segments_left;
1604 tr->num_segments = 0xFF;
1607 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1609 sr_localsid_trace_t *tr =
1610 vlib_add_trace (vm, node, b2, sizeof (*tr));
1611 tr->num_segments = 0;
1612 clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1613 sizeof (tr->localsid.as_u8));
1614 tr->behavior = ls2->behavior;
1615 if (ip2 == vlib_buffer_get_current (b2))
1617 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1618 && sr2->type == ROUTING_HEADER_TYPE_SR)
1620 clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1622 sr2->length * 8 / sizeof (ip6_address_t);
1623 tr->segments_left = sr2->segments_left;
1627 tr->num_segments = 0xFF;
1630 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1632 sr_localsid_trace_t *tr =
1633 vlib_add_trace (vm, node, b3, sizeof (*tr));
1634 tr->num_segments = 0;
1635 clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1636 sizeof (tr->localsid.as_u8));
1637 tr->behavior = ls3->behavior;
1638 if (ip3 == vlib_buffer_get_current (b3))
1640 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1641 && sr3->type == ROUTING_HEADER_TYPE_SR)
1643 clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1645 sr3->length * 8 / sizeof (ip6_address_t);
1646 tr->segments_left = sr3->segments_left;
1650 tr->num_segments = 0xFF;
1653 vlib_increment_combined_counter
1655 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1656 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1657 1, vlib_buffer_length_in_chain (vm, b0));
1659 vlib_increment_combined_counter
1661 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1662 &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1663 1, vlib_buffer_length_in_chain (vm, b1));
1665 vlib_increment_combined_counter
1667 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1668 &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1669 1, vlib_buffer_length_in_chain (vm, b2));
1671 vlib_increment_combined_counter
1673 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1674 &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1675 1, vlib_buffer_length_in_chain (vm, b3));
1677 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1678 n_left_to_next, bi0, bi1, bi2, bi3,
1679 next0, next1, next2, next3);
1682 /* Single loop for potentially the last three packets */
1683 while (n_left_from > 0 && n_left_to_next > 0)
1687 ip6_header_t *ip0 = 0;
1688 ip6_ext_header_t *prev0;
1689 ip6_sr_header_t *sr0;
1690 u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1691 ip6_sr_localsid_t *ls0;
1698 n_left_to_next -= 1;
1700 b0 = vlib_get_buffer (vm, bi0);
1701 ip0 = vlib_buffer_get_current (b0);
1703 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1705 /* Lookup the SR End behavior based on IP DA (adj) */
1707 pool_elt_at_index (sm->localsids,
1708 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1710 /* SRH processing */
1711 end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1714 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1716 sr_localsid_trace_t *tr =
1717 vlib_add_trace (vm, node, b0, sizeof (*tr));
1718 tr->num_segments = 0;
1719 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1720 sizeof (tr->localsid.as_u8));
1721 tr->behavior = ls0->behavior;
1722 if (ip0 == vlib_buffer_get_current (b0))
1724 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1725 && sr0->type == ROUTING_HEADER_TYPE_SR)
1727 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1729 sr0->length * 8 / sizeof (ip6_address_t);
1730 tr->segments_left = sr0->segments_left;
1734 tr->num_segments = 0xFF;
1737 vlib_increment_combined_counter
1739 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1740 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1741 1, vlib_buffer_length_in_chain (vm, b0));
1743 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1744 n_left_to_next, bi0, next0);
1746 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1748 return from_frame->n_vectors;
1752 VLIB_REGISTER_NODE (sr_localsid_node) = {
1753 .function = sr_localsid_fn,
1754 .name = "sr-localsid",
1755 .vector_size = sizeof (u32),
1756 .format_trace = format_sr_localsid_trace,
1757 .type = VLIB_NODE_TYPE_INTERNAL,
1758 .n_errors = SR_LOCALSID_N_ERROR,
1759 .error_strings = sr_localsid_error_strings,
1760 .n_next_nodes = SR_LOCALSID_N_NEXT,
1762 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1763 foreach_sr_localsid_next
1770 * @brief SR LocalSID uN graph node. Supports all default SR Endpoint without decaps
1773 sr_localsid_un_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1774 vlib_frame_t * from_frame)
1776 u32 n_left_from, next_index, *from, *to_next;
1777 ip6_sr_main_t *sm = &sr_main;
1778 from = vlib_frame_vector_args (from_frame);
1779 n_left_from = from_frame->n_vectors;
1780 next_index = node->cached_next_index;
1781 u32 thread_index = vm->thread_index;
1783 while (n_left_from > 0)
1786 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1789 while (n_left_from >= 8 && n_left_to_next >= 4)
1791 u32 bi0, bi1, bi2, bi3;
1792 vlib_buffer_t *b0, *b1, *b2, *b3;
1793 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1794 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1795 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1796 u32 next0, next1, next2, next3;
1797 next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1798 ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1800 /* Prefetch next iteration. */
1802 vlib_buffer_t *p4, *p5, *p6, *p7;
1804 p4 = vlib_get_buffer (vm, from[4]);
1805 p5 = vlib_get_buffer (vm, from[5]);
1806 p6 = vlib_get_buffer (vm, from[6]);
1807 p7 = vlib_get_buffer (vm, from[7]);
1809 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1810 vlib_prefetch_buffer_header (p4, LOAD);
1811 vlib_prefetch_buffer_header (p5, LOAD);
1812 vlib_prefetch_buffer_header (p6, LOAD);
1813 vlib_prefetch_buffer_header (p7, LOAD);
1815 clib_prefetch_store (p4->data);
1816 clib_prefetch_store (p5->data);
1817 clib_prefetch_store (p6->data);
1818 clib_prefetch_store (p7->data);
1821 to_next[0] = bi0 = from[0];
1822 to_next[1] = bi1 = from[1];
1823 to_next[2] = bi2 = from[2];
1824 to_next[3] = bi3 = from[3];
1828 n_left_to_next -= 4;
1830 b0 = vlib_get_buffer (vm, bi0);
1831 b1 = vlib_get_buffer (vm, bi1);
1832 b2 = vlib_get_buffer (vm, bi2);
1833 b3 = vlib_get_buffer (vm, bi3);
1835 ip0 = vlib_buffer_get_current (b0);
1836 ip1 = vlib_buffer_get_current (b1);
1837 ip2 = vlib_buffer_get_current (b2);
1838 ip3 = vlib_buffer_get_current (b3);
1841 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1843 ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1845 ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1847 ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1850 pool_elt_at_index (sm->localsids,
1851 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1853 pool_elt_at_index (sm->localsids,
1854 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1856 pool_elt_at_index (sm->localsids,
1857 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1859 pool_elt_at_index (sm->localsids,
1860 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1862 end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
1863 ls0->end_psp, prev0);
1864 end_un_srh_processing (node, b1, ip1, sr1, ls1, &next1,
1865 ls1->end_psp, prev1);
1866 end_un_srh_processing (node, b2, ip2, sr2, ls2, &next2,
1867 ls2->end_psp, prev2);
1868 end_un_srh_processing (node, b3, ip3, sr3, ls3, &next3,
1869 ls3->end_psp, prev3);
1871 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1873 sr_localsid_trace_t *tr =
1874 vlib_add_trace (vm, node, b0, sizeof (*tr));
1875 tr->num_segments = 0;
1876 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1877 sizeof (tr->localsid.as_u8));
1878 tr->behavior = ls0->behavior;
1879 if (ip0 == vlib_buffer_get_current (b0))
1881 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1882 && sr0->type == ROUTING_HEADER_TYPE_SR)
1884 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1886 sr0->length * 8 / sizeof (ip6_address_t);
1887 tr->segments_left = sr0->segments_left;
1891 tr->num_segments = 0xFF;
1894 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1896 sr_localsid_trace_t *tr =
1897 vlib_add_trace (vm, node, b1, sizeof (*tr));
1898 tr->num_segments = 0;
1899 clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1900 sizeof (tr->localsid.as_u8));
1901 tr->behavior = ls1->behavior;
1902 if (ip1 == vlib_buffer_get_current (b1))
1904 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1905 && sr1->type == ROUTING_HEADER_TYPE_SR)
1907 clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1909 sr1->length * 8 / sizeof (ip6_address_t);
1910 tr->segments_left = sr1->segments_left;
1914 tr->num_segments = 0xFF;
1917 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1919 sr_localsid_trace_t *tr =
1920 vlib_add_trace (vm, node, b2, sizeof (*tr));
1921 tr->num_segments = 0;
1922 clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1923 sizeof (tr->localsid.as_u8));
1924 tr->behavior = ls2->behavior;
1925 if (ip2 == vlib_buffer_get_current (b2))
1927 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1928 && sr2->type == ROUTING_HEADER_TYPE_SR)
1930 clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1932 sr2->length * 8 / sizeof (ip6_address_t);
1933 tr->segments_left = sr2->segments_left;
1937 tr->num_segments = 0xFF;
1940 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1942 sr_localsid_trace_t *tr =
1943 vlib_add_trace (vm, node, b3, sizeof (*tr));
1944 tr->num_segments = 0;
1945 clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1946 sizeof (tr->localsid.as_u8));
1947 tr->behavior = ls3->behavior;
1948 if (ip3 == vlib_buffer_get_current (b3))
1950 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1951 && sr3->type == ROUTING_HEADER_TYPE_SR)
1953 clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1955 sr3->length * 8 / sizeof (ip6_address_t);
1956 tr->segments_left = sr3->segments_left;
1960 tr->num_segments = 0xFF;
1963 vlib_increment_combined_counter
1965 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1966 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1967 1, vlib_buffer_length_in_chain (vm, b0));
1969 vlib_increment_combined_counter
1971 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1972 &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1973 1, vlib_buffer_length_in_chain (vm, b1));
1975 vlib_increment_combined_counter
1977 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1978 &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1979 1, vlib_buffer_length_in_chain (vm, b2));
1981 vlib_increment_combined_counter
1983 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1984 &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1985 1, vlib_buffer_length_in_chain (vm, b3));
1987 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1988 n_left_to_next, bi0, bi1, bi2, bi3,
1989 next0, next1, next2, next3);
1992 /* Single loop for potentially the last three packets */
1993 while (n_left_from > 0 && n_left_to_next > 0)
1997 ip6_header_t *ip0 = 0;
1998 ip6_ext_header_t *prev0;
1999 ip6_sr_header_t *sr0;
2000 u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2001 ip6_sr_localsid_t *ls0;
2008 n_left_to_next -= 1;
2010 b0 = vlib_get_buffer (vm, bi0);
2011 ip0 = vlib_buffer_get_current (b0);
2013 ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
2015 /* Lookup the SR End behavior based on IP DA (adj) */
2017 pool_elt_at_index (sm->localsids,
2018 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2020 /* SRH processing */
2021 end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
2022 ls0->end_psp, prev0);
2024 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2026 sr_localsid_trace_t *tr =
2027 vlib_add_trace (vm, node, b0, sizeof (*tr));
2028 tr->num_segments = 0;
2029 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2030 sizeof (tr->localsid.as_u8));
2031 tr->behavior = ls0->behavior;
2032 if (ip0 == vlib_buffer_get_current (b0))
2034 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
2035 && sr0->type == ROUTING_HEADER_TYPE_SR)
2037 clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
2039 sr0->length * 8 / sizeof (ip6_address_t);
2040 tr->segments_left = sr0->segments_left;
2044 tr->num_segments = 0xFF;
2047 vlib_increment_combined_counter
2049 SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
2050 &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
2051 1, vlib_buffer_length_in_chain (vm, b0));
2053 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2054 n_left_to_next, bi0, next0);
2056 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2058 return from_frame->n_vectors;
2062 VLIB_REGISTER_NODE (sr_localsid_un_node) = {
2063 .function = sr_localsid_un_fn,
2064 .name = "sr-localsid-un",
2065 .vector_size = sizeof (u32),
2066 .format_trace = format_sr_localsid_trace,
2067 .type = VLIB_NODE_TYPE_INTERNAL,
2068 .n_errors = SR_LOCALSID_N_ERROR,
2069 .error_strings = sr_localsid_error_strings,
2070 .n_next_nodes = SR_LOCALSID_N_NEXT,
2072 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2073 foreach_sr_localsid_next
2080 sr_localsid_un_perf_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
2081 vlib_frame_t * from_frame)
2083 u32 n_left_from, next_index, *from, *to_next;
2084 ip6_sr_main_t *sm = &sr_main;
2085 from = vlib_frame_vector_args (from_frame);
2086 n_left_from = from_frame->n_vectors;
2087 next_index = node->cached_next_index;
2088 u32 thread_index = vm->thread_index;
2090 while (n_left_from > 0)
2093 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2096 while (n_left_from >= 8 && n_left_to_next >= 4)
2098 u32 bi0, bi1, bi2, bi3;
2099 vlib_buffer_t *b0, *b1, *b2, *b3;
2100 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2101 u32 next0, next1, next2, next3;
2102 next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2103 ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
2105 /* Prefetch next iteration. */
2107 vlib_buffer_t *p4, *p5, *p6, *p7;
2109 p4 = vlib_get_buffer (vm, from[4]);
2110 p5 = vlib_get_buffer (vm, from[5]);
2111 p6 = vlib_get_buffer (vm, from[6]);
2112 p7 = vlib_get_buffer (vm, from[7]);
2114 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2115 vlib_prefetch_buffer_header (p4, LOAD);
2116 vlib_prefetch_buffer_header (p5, LOAD);
2117 vlib_prefetch_buffer_header (p6, LOAD);
2118 vlib_prefetch_buffer_header (p7, LOAD);
2120 clib_prefetch_store (p4->data);
2121 clib_prefetch_store (p5->data);
2122 clib_prefetch_store (p6->data);
2123 clib_prefetch_store (p7->data);
2126 to_next[0] = bi0 = from[0];
2127 to_next[1] = bi1 = from[1];
2128 to_next[2] = bi2 = from[2];
2129 to_next[3] = bi3 = from[3];
2133 n_left_to_next -= 4;
2135 b0 = vlib_get_buffer (vm, bi0);
2136 b1 = vlib_get_buffer (vm, bi1);
2137 b2 = vlib_get_buffer (vm, bi2);
2138 b3 = vlib_get_buffer (vm, bi3);
2140 ip0 = vlib_buffer_get_current (b0);
2141 ip1 = vlib_buffer_get_current (b1);
2142 ip2 = vlib_buffer_get_current (b2);
2143 ip3 = vlib_buffer_get_current (b3);
2146 pool_elt_at_index (sm->localsids,
2147 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2149 pool_elt_at_index (sm->localsids,
2150 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2152 pool_elt_at_index (sm->localsids,
2153 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2155 pool_elt_at_index (sm->localsids,
2156 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2158 end_un_processing (ip0, ls0);
2159 end_un_processing (ip1, ls1);
2160 end_un_processing (ip2, ls2);
2161 end_un_processing (ip3, ls3);
2163 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2165 sr_localsid_trace_t *tr =
2166 vlib_add_trace (vm, node, b0, sizeof (*tr));
2167 tr->num_segments = 0;
2168 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2169 sizeof (tr->localsid.as_u8));
2170 tr->behavior = ls0->behavior;
2173 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2175 sr_localsid_trace_t *tr =
2176 vlib_add_trace (vm, node, b1, sizeof (*tr));
2177 tr->num_segments = 0;
2178 clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
2179 sizeof (tr->localsid.as_u8));
2180 tr->behavior = ls1->behavior;
2183 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2185 sr_localsid_trace_t *tr =
2186 vlib_add_trace (vm, node, b2, sizeof (*tr));
2187 tr->num_segments = 0;
2188 clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
2189 sizeof (tr->localsid.as_u8));
2190 tr->behavior = ls2->behavior;
2193 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2195 sr_localsid_trace_t *tr =
2196 vlib_add_trace (vm, node, b3, sizeof (*tr));
2197 tr->num_segments = 0;
2198 clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
2199 sizeof (tr->localsid.as_u8));
2200 tr->behavior = ls3->behavior;
2203 vlib_increment_combined_counter
2204 (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2205 1, vlib_buffer_length_in_chain (vm, b0));
2207 vlib_increment_combined_counter
2208 (&(sm->sr_ls_valid_counters), thread_index, ls1 - sm->localsids,
2209 1, vlib_buffer_length_in_chain (vm, b1));
2211 vlib_increment_combined_counter
2212 (&(sm->sr_ls_valid_counters), thread_index, ls2 - sm->localsids,
2213 1, vlib_buffer_length_in_chain (vm, b2));
2215 vlib_increment_combined_counter
2216 (&(sm->sr_ls_valid_counters), thread_index, ls3 - sm->localsids,
2217 1, vlib_buffer_length_in_chain (vm, b3));
2219 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2220 n_left_to_next, bi0, bi1, bi2, bi3,
2221 next0, next1, next2, next3);
2224 /* Single loop for potentially the last three packets */
2225 while (n_left_from > 0 && n_left_to_next > 0)
2229 ip6_header_t *ip0 = 0;
2230 u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2231 ip6_sr_localsid_t *ls0;
2238 n_left_to_next -= 1;
2240 b0 = vlib_get_buffer (vm, bi0);
2241 ip0 = vlib_buffer_get_current (b0);
2243 /* Lookup the SR End behavior based on IP DA (adj) */
2245 pool_elt_at_index (sm->localsids,
2246 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2248 /* SRH processing */
2249 end_un_processing (ip0, ls0);
2251 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2253 sr_localsid_trace_t *tr =
2254 vlib_add_trace (vm, node, b0, sizeof (*tr));
2255 tr->num_segments = 0;
2256 clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2257 sizeof (tr->localsid.as_u8));
2258 tr->behavior = ls0->behavior;
2261 vlib_increment_combined_counter
2262 (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2263 1, vlib_buffer_length_in_chain (vm, b0));
2265 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2266 n_left_to_next, bi0, next0);
2268 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2270 return from_frame->n_vectors;
2274 VLIB_REGISTER_NODE (sr_localsid_un_perf_node) = {
2275 .function = sr_localsid_un_perf_fn,
2276 .name = "sr-localsid-un-perf",
2277 .vector_size = sizeof (u32),
2278 .format_trace = format_sr_localsid_trace,
2279 .type = VLIB_NODE_TYPE_INTERNAL,
2280 .n_errors = SR_LOCALSID_N_ERROR,
2281 .error_strings = sr_localsid_error_strings,
2282 .n_next_nodes = SR_LOCALSID_N_NEXT,
2284 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2285 foreach_sr_localsid_next
2292 format_sr_dpo (u8 * s, va_list * args)
2294 index_t index = va_arg (*args, index_t);
2295 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
2297 return (format (s, "SR: localsid_index:[%d]", index));
2300 const static dpo_vft_t sr_loc_vft = {
2301 .dv_lock = sr_dpo_lock,
2302 .dv_unlock = sr_dpo_unlock,
2303 .dv_format = format_sr_dpo,
2306 const static char *const sr_loc_ip6_nodes[] = {
2311 const static char *const *const sr_loc_nodes[DPO_PROTO_NUM] = {
2312 [DPO_PROTO_IP6] = sr_loc_ip6_nodes,
2315 const static char *const sr_loc_d_ip6_nodes[] = {
2320 const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
2321 [DPO_PROTO_IP6] = sr_loc_d_ip6_nodes,
2324 const static char *const sr_loc_un_ip6_nodes[] = {
2329 const static char *const *const sr_loc_un_nodes[DPO_PROTO_NUM] = {
2330 [DPO_PROTO_IP6] = sr_loc_un_ip6_nodes,
2333 const static char *const sr_loc_un_perf_ip6_nodes[] = {
2334 "sr-localsid-un-perf",
2338 const static char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM] = {
2339 [DPO_PROTO_IP6] = sr_loc_un_perf_ip6_nodes,
2342 /*************************** SR LocalSID plugins ******************************/
2344 * @brief SR LocalSID plugin registry
2347 sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
2348 u8 * keyword_str, u8 * def_str,
2349 u8 * params_str, u8 prefix_length,
2351 format_function_t * ls_format,
2352 unformat_function_t * ls_unformat,
2353 sr_plugin_callback_t * creation_fn,
2354 sr_plugin_callback_t * removal_fn)
2356 ip6_sr_main_t *sm = &sr_main;
2359 sr_localsid_fn_registration_t *plugin;
2361 /* Did this function exist? If so update it */
2362 p = hash_get_mem (sm->plugin_functions_by_key, fn_name);
2365 plugin = pool_elt_at_index (sm->plugin_functions, p[0]);
2367 /* Else create a new one and set hash key */
2370 pool_get (sm->plugin_functions, plugin);
2371 hash_set_mem (sm->plugin_functions_by_key, fn_name,
2372 plugin - sm->plugin_functions);
2375 clib_memset (plugin, 0, sizeof (*plugin));
2377 plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
2378 plugin->sr_localsid_function_number += SR_BEHAVIOR_LAST;
2379 plugin->prefix_length = prefix_length;
2380 plugin->ls_format = ls_format;
2381 plugin->ls_unformat = ls_unformat;
2382 plugin->creation = creation_fn;
2383 plugin->removal = removal_fn;
2384 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
2385 plugin->function_name = format (0, "%s%c", fn_name, 0);
2386 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
2387 plugin->def_str = format (0, "%s%c", def_str, 0);
2388 plugin->params_str = format (0, "%s%c", params_str, 0);
2390 return plugin->sr_localsid_function_number;
2394 * @brief CLI function to 'show' all available SR LocalSID behaviors
2396 static clib_error_t *
2397 show_sr_localsid_behaviors_command_fn (vlib_main_t * vm,
2398 unformat_input_t * input,
2399 vlib_cli_command_t * cmd)
2401 ip6_sr_main_t *sm = &sr_main;
2402 sr_localsid_fn_registration_t *plugin;
2403 sr_localsid_fn_registration_t **plugins_vec = 0;
2406 vlib_cli_output (vm,
2407 "SR LocalSIDs behaviors:\n-----------------------\n\n");
2410 pool_foreach (plugin, sm->plugin_functions)
2411 { vec_add1 (plugins_vec, plugin); }
2414 /* Print static behaviors */
2415 vlib_cli_output (vm, "Default behaviors:\n"
2416 "\tEnd\t-> Endpoint.\n"
2417 "\tEnd.X\t-> Endpoint with Layer-3 cross-connect.\n"
2418 "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2419 "\tEnd.T\t-> Endpoint with specific IPv6 table lookup.\n"
2420 "\t\tParameters: '<fib_table>'\n"
2421 "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
2422 "\t\tParameters: '<iface>'\n"
2423 "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
2424 "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2425 "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
2426 "\t\tParameters: '<iface> <ip4_next_hop>'\n"
2427 "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
2428 "\t\tParameters: '<ip6_fib_table>'\n"
2429 "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
2430 "\t\tParameters: '<ip4_fib_table>'\n");
2431 vlib_cli_output (vm, "Plugin behaviors:\n");
2432 for (i = 0; i < vec_len (plugins_vec); i++)
2434 plugin = plugins_vec[i];
2435 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
2437 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
2443 VLIB_CLI_COMMAND (show_sr_localsid_behaviors_command, static) = {
2444 .path = "show sr localsids behaviors",
2445 .short_help = "show sr localsids behaviors",
2446 .function = show_sr_localsid_behaviors_command_fn,
2451 * @brief SR LocalSID initialization
2454 sr_localsids_init (vlib_main_t * vm)
2456 /* Init memory for function keys */
2457 ip6_sr_main_t *sm = &sr_main;
2458 mhash_init (&sm->sr_localsids_index_hash, sizeof (uword),
2459 sizeof (sr_localsid_key_t));
2460 /* Init SR behaviors DPO type */
2461 sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes);
2462 /* Init SR behaviors DPO type */
2463 sr_localsid_d_dpo_type =
2464 dpo_register_new_type (&sr_loc_vft, sr_loc_d_nodes);
2465 /* Init SR bhaviors DPO type */
2466 sr_localsid_un_dpo_type =
2467 dpo_register_new_type (&sr_loc_vft, sr_loc_un_nodes);
2468 sr_localsid_un_perf_dpo_type =
2469 dpo_register_new_type (&sr_loc_vft, sr_loc_un_perf_nodes);
2470 /* Init memory for localsid plugins */
2471 sm->plugin_functions_by_key = hash_create_string (0, sizeof (uword));
2475 VLIB_INIT_FUNCTION (sr_localsids_init);
2477 * fd.io coding-style-patch-verification: ON
2480 * eval: (c-set-style "gnu")