FD.io VPP  v21.01
Vector Packet Processing
sr_localsid.c
Go to the documentation of this file.
1 /*
2  * sr_localsid.c: ipv6 segment routing Endpoint behaviors
3  *
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:
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 
18 /**
19  * @file
20  * @brief Processing of packets with a SRH
21  *
22  * CLI to define new Segment Routing End processing functions.
23  * Graph node to support such functions.
24  *
25  * Each function associates an SRv6 segment (IPv6 address) with an specific
26  * Segment Routing function.
27  *
28  */
29 
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>
39 
40 #include <vppinfra/error.h>
41 #include <vppinfra/elog.h>
42 
43 /**
44  * @brief Dynamically added SR localsid DPO type
45  */
50 
51 static void
53  u16 pref_len)
54 {
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;
58 }
59 
60 /**
61  * @brief SR localsid add/del
62  *
63  * Function to add or delete SR LocalSIDs.
64  *
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.
73  *
74  * @return 0 on success, error otherwise.
75  */
76 int
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)
81 {
82  ip6_sr_main_t *sm = &sr_main;
83  uword *p;
84  int rv;
85  u8 pref_length = 128;
88 
89  ip6_sr_localsid_t *ls = 0;
90 
91  dpo_id_t dpo = DPO_INVALID;
92 
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);
96 
97  if (p)
98  {
99  if (is_del)
100  {
101  /* Retrieve localsid */
102  ls = pool_elt_at_index (sm->localsids, p[0]);
103  if (ls->behavior >= SR_BEHAVIOR_LAST)
104  {
105  plugin = pool_elt_at_index (sm->plugin_functions,
106  ls->behavior - SR_BEHAVIOR_LAST);
107  pref_length = plugin->prefix_length;
108  }
109 
110  if (localsid_prefix_len != 0)
111  {
112  pref_length = localsid_prefix_len;
113  }
114 
115  /* Delete FIB entry */
116  fib_prefix_t pfx = {
118  .fp_len = pref_length,
119  .fp_addr = {
120  .ip6 = *localsid_addr,
121  }
122  };
123 
125  (FIB_PROTOCOL_IP6, fib_table), &pfx,
126  FIB_SOURCE_SR);
127 
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);
132 
133  if (ls->behavior >= SR_BEHAVIOR_LAST)
134  {
135  /* Callback plugin removal function */
136  rv = plugin->removal (ls);
137  }
138 
139  /* Delete localsid registry */
140  pool_put (sm->localsids, ls);
141  mhash_unset (&sm->sr_localsids_index_hash, &key, NULL);
142  return 0;
143  }
144  else /* create with function already existing; complain */
145  return -1;
146  }
147  else
148  /* delete; localsid does not exist; complain */
149  if (is_del)
150  return -2;
151 
152  if (behavior >= SR_BEHAVIOR_LAST)
153  {
154  sr_localsid_fn_registration_t *plugin = 0;
155  plugin =
157  pref_length = plugin->prefix_length;
158  }
159 
160  if (localsid_prefix_len != 0)
161  {
162  pref_length = localsid_prefix_len;
163  }
164 
165  /* Check whether there exists a FIB entry with such address */
166  fib_prefix_t pfx = {
168  .fp_len = pref_length,
169  };
170 
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;
174 
175  /* Lookup the FIB index associated to the table id provided */
176  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, fib_table);
177  if (fib_index == ~0)
178  return -3;
179 
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)
184 
185  /* Create a new localsid registry */
186  pool_get (sm->localsids, ls);
187  clib_memset (ls, 0, sizeof (*ls));
188 
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;
195  switch (behavior)
196  {
197  case SR_BEHAVIOR_END:
198  break;
199  case SR_BEHAVIOR_END_UN:
201  if (usid_len)
202  {
203  int usid_width;
204  clib_memcpy (&ls->usid_block, localsid_addr,
205  sizeof (ip6_address_t));
206 
207  usid_width = pref_length - usid_len;
208  ip6_address_mask_from_width (&ls->usid_block_mask, usid_width);
209 
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;
214  }
215  break;
216  case SR_BEHAVIOR_X:
217  ls->sw_if_index = sw_if_index;
218  clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
219  break;
220  case SR_BEHAVIOR_T:
221  ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
222  break;
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));
226  break;
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));
230  break;
231  case SR_BEHAVIOR_DT6:
232  ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
233  break;
234  case SR_BEHAVIOR_DT4:
235  ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP4, sw_if_index);
236  break;
237  case SR_BEHAVIOR_DX2:
238  ls->sw_if_index = sw_if_index;
239  ls->vlan_index = vlan_index;
240  break;
241  }
242 
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)
246  {
247  adj_index_t nh_adj_index = ADJ_INDEX_INVALID;
248 
249  /* Retrieve the adjacency corresponding to the (OIF, next_hop) */
250  if (ls->behavior == SR_BEHAVIOR_DX6 || ls->behavior == SR_BEHAVIOR_X)
252  nh_addr, sw_if_index);
253 
254  else if (ls->behavior == SR_BEHAVIOR_DX4)
256  nh_addr, sw_if_index);
257 
258  /* Check for ADJ creation error. If so panic */
259  if (nh_adj_index == ADJ_INDEX_INVALID)
260  {
261  pool_put (sm->localsids, ls);
262  return -5;
263  }
264 
265  ls->nh_adj = nh_adj_index;
266  }
267 
268  /* Set DPO */
269  if (ls->behavior == SR_BEHAVIOR_END || ls->behavior == SR_BEHAVIOR_X
270  || ls->behavior == SR_BEHAVIOR_T)
272  else if (ls->behavior == SR_BEHAVIOR_END_UN)
274  ls - sm->localsids);
275  else if (ls->behavior == SR_BEHAVIOR_END_UN_PERF)
277  ls - sm->localsids);
278  else if (ls->behavior > SR_BEHAVIOR_D_FIRST
279  && ls->behavior < SR_BEHAVIOR_LAST)
281  else if (ls->behavior >= SR_BEHAVIOR_LAST)
282  {
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);
290  if (rv)
291  {
292  pool_put (sm->localsids, ls);
293  return -6;
294  }
295  dpo_set (&dpo, plugin->dpo, DPO_PROTO_IP6, ls - sm->localsids);
296  }
297 
298  /* Set hash key for searching localsid by address */
299  mhash_set (&sm->sr_localsids_index_hash, &key, ls - sm->localsids, NULL);
300 
303  dpo_reset (&dpo);
304 
305  /* Set counter to zero */
307  ls - sm->localsids);
309  ls - sm->localsids);
310 
312  ls - sm->localsids);
314  ls - sm->localsids);
315 
316  return 0;
317 }
318 
319 /**
320  * @brief SR LocalSID CLI function.
321  *
322  * @see sr_cli_localsid
323  */
324 static clib_error_t *
326  vlib_cli_command_t * cmd)
327 {
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;
331  int prefix_len = 0;
332  int is_del = 0;
333  int end_psp = 0;
334  ip6_address_t resulting_address;
335  ip46_address_t next_hop;
336  char address_set = 0;
337  char behavior = 0;
338  void *ls_plugin_mem = 0;
339  int usid_size = 0;
340 
341  int rv;
342 
343  clib_memset (&resulting_address, 0, sizeof (ip6_address_t));
344  ip46_address_reset (&next_hop);
345 
347  {
348  if (unformat (input, "del"))
349  is_del = 1;
350  else if (!address_set
351  && unformat (input, "prefix %U/%u", unformat_ip6_address,
352  &resulting_address, &prefix_len))
353  address_set = 1;
354  else if (!address_set
355  && unformat (input, "address %U", unformat_ip6_address,
356  &resulting_address))
357  address_set = 1;
358  else if (!address_set
359  && unformat (input, "addr %U", unformat_ip6_address,
360  &resulting_address))
361  address_set = 1;
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"))
366  {
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;
392  else
393  {
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;
397 
398  /* Create a vector out of the plugin pool as recommended */
399  /* *INDENT-OFF* */
400  pool_foreach (plugin, sm->plugin_functions)
401  {
402  vec_add1 (vec_plugins, plugin);
403  }
404  /* *INDENT-ON* */
405 
406  vec_foreach (plugin_it, vec_plugins)
407  {
408  if (unformat
409  (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
410  {
411  behavior = (*plugin_it)->sr_localsid_function_number;
412  break;
413  }
414  }
415  }
416 
417  if (!behavior)
418  {
419  if (unformat (input, "end"))
420  behavior = SR_BEHAVIOR_END;
421  else
422  break;
423  }
424  }
425  else if (!end_psp && unformat (input, "psp"))
426  end_psp = 1;
427  else
428  break;
429  }
430 
431  if (!behavior && end_psp)
432  behavior = SR_BEHAVIOR_END;
433 
434  if (usid_size)
435  {
436  if (prefix_len < usid_size)
437  return clib_error_return (0,
438  "Error: Prefix length must be greater"
439  " than uSID length.");
440 
441  if (usid_size != 16 && usid_size != 32)
442  return clib_error_return (0,
443  "Error: Invalid uSID length (16 or 32).");
444 
445  if ((prefix_len - usid_size) & 0x7)
446  return clib_error_return (0,
447  "Error: Prefix Length must be multiple of 8.");
448  }
449 
450  if (!address_set)
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");
462 
463  rv =
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);
467 
468  if (behavior == SR_BEHAVIOR_END_UN_PERF)
469  {
470  if (rv == 0)
471  {
472  u16 perf_len;
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);
477  }
478  }
479 
480  switch (rv)
481  {
482  case 0:
483  break;
484  case 1:
485  return 0;
486  case -1:
487  return clib_error_return (0,
488  "Identical localsid already exists. Requested localsid not created.");
489  case -2:
490  return clib_error_return (0,
491  "The requested localsid could not be deleted. SR localsid not found");
492  case -3:
493  return clib_error_return (0, "FIB table %u does not exist", fib_index);
494  case -4:
495  return clib_error_return (0, "There is already one FIB entry for the"
496  "requested localsid non segment routing related");
497  case -5:
498  return clib_error_return (0,
499  "Could not create ARP/ND entry for such next_hop. Internal error.");
500  case -6:
501  return clib_error_return (0,
502  "Error on the plugin based localsid creation.");
503  default:
504  return clib_error_return (0, "BUG: sr localsid returns %d", rv);
505  }
506  return 0;
507 }
508 
509 /* *INDENT-OFF* */
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",
514  .long_help =
515  "Create SR LocalSID and binds it to a particular behavior\n"
516  "Arguments:\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"
520  "\n\tBehaviors:\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,
536 };
537 /* *INDENT-ON* */
538 
539 /**
540  * @brief CLI function to 'show' all SR LocalSIDs on console.
541  */
542 static clib_error_t *
544  vlib_cli_command_t * cmd)
545 {
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;
550  int i;
551 
552  vlib_cli_output (vm, "SRv6 - My LocalSID Table:");
553  vlib_cli_output (vm, "=========================");
554  /* *INDENT-OFF* */
555  pool_foreach (ls, sm->localsids) { vec_add1 (localsid_list, ls); }
556  /* *INDENT-ON* */
557  for (i = 0; i < vec_len (localsid_list); i++)
558  {
559  ls = localsid_list[i];
560  switch (ls->behavior)
561  {
562  case SR_BEHAVIOR_END:
563  vlib_cli_output (vm, "\tAddress: \t%U\n\tBehavior: \tEnd",
565  break;
566  case SR_BEHAVIOR_END_UN:
567  vlib_cli_output (vm,
568  "\tAddress: \t%U\n\tBehavior: \tEnd (flex) [uSID:\t%U/%d, length: %d]",
571  ls->usid_index * 8, ls->usid_len * 8);
572  break;
574  vlib_cli_output (vm,
575  "\tAddress: \t%U\n\tBehavior: \tEnd [uSID:\t%U/%d, length: %d]",
578  ls->usid_index * 8, ls->usid_len * 8);
579  break;
580  case SR_BEHAVIOR_X:
581  vlib_cli_output (vm,
582  "\tAddress: \t%U/%u\n\tBehavior: \tX (Endpoint with Layer-3 cross-connect)"
583  "\n\tIface: \t%U\n\tNext hop: \t%U",
587  format_ip6_address, &ls->next_hop.ip6);
588  break;
589  case SR_BEHAVIOR_T:
590  vlib_cli_output (vm,
591  "\tAddress: \t%U/%u\n\tBehavior: \tT (Endpoint with specific IPv6 table lookup)"
592  "\n\tTable: \t%u",
597  break;
598  case SR_BEHAVIOR_DX4:
599  vlib_cli_output (vm,
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",
605  format_ip4_address, &ls->next_hop.ip4);
606  break;
607  case SR_BEHAVIOR_DX6:
608  vlib_cli_output (vm,
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",
614  format_ip6_address, &ls->next_hop.ip6);
615  break;
616  case SR_BEHAVIOR_DX2:
617  if (ls->vlan_index == (u32) ~ 0)
618  vlib_cli_output (vm,
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,
623  ls->sw_if_index);
624  else
625  vlib_cli_output (vm,
626  "Unsupported yet. (DX2 with egress VLAN rewrite)");
627  break;
628  case SR_BEHAVIOR_DT6:
629  vlib_cli_output (vm,
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,
635  break;
636  case SR_BEHAVIOR_DT4:
637  vlib_cli_output (vm,
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,
643  break;
644  default:
645  if (ls->behavior >= SR_BEHAVIOR_LAST)
646  {
649  ls->behavior - SR_BEHAVIOR_LAST);
650 
651  vlib_cli_output (vm, "\tAddress: \t%U/%u\n"
652  "\tBehavior: \t%s (%s)\n\t%U",
654  ls->localsid_prefix_len, plugin->keyword_str,
655  plugin->def_str, plugin->ls_format,
656  ls->plugin_mem);
657  }
658  else
659  //Should never get here...
660  vlib_cli_output (vm, "Internal error");
661  break;
662  }
663  if (ls->end_psp)
664  vlib_cli_output (vm, "\tPSP: \tTrue\n");
665 
666  /* Print counters */
667  vlib_counter_t valid, 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, "--------------------");
675  }
676  return 0;
677 }
678 
679 /* *INDENT-OFF* */
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,
684 };
685 /* *INDENT-ON* */
686 
687 /**
688  * @brief Function to 'clear' ALL SR localsid counters
689  */
690 static clib_error_t *
692  unformat_input_t * input,
693  vlib_cli_command_t * cmd)
694 {
695  ip6_sr_main_t *sm = &sr_main;
696 
699 
700  return 0;
701 }
702 
703 /* *INDENT-OFF* */
704 VLIB_CLI_COMMAND (clear_sr_localsid_counters_command, static) = {
705  .path = "clear sr localsid-counters",
706  .short_help = "clear sr localsid-counters",
708 };
709 /* *INDENT-ON* */
710 
711 /************************ SR LocalSID graphs node ****************************/
712 /**
713  * @brief SR localsid node trace
714  */
715 typedef struct
716 {
717  ip6_address_t localsid;
719  u8 sr[256];
723 
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")
731 
732 typedef enum
733 {
734 #define _(sym,str) SR_LOCALSID_ERROR_##sym,
736 #undef _
739 
740 static char *sr_localsid_error_strings[] = {
741 #define _(sym,string) string,
743 #undef _
744 };
745 
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")
753 
754 typedef enum
755 {
756 #define _(s,n) SR_LOCALSID_NEXT_##s,
758 #undef _
761 
762 /**
763  * @brief SR LocalSID graph node trace function
764  *
765  * @see sr_localsid
766  */
767 u8 *
768 format_sr_localsid_trace (u8 * s, va_list * args)
769 {
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 *);
773 
774  s =
775  format (s, "SR-LOCALSID:\n\tLocalsid: %U\n", format_ip6_address,
776  &t->localsid);
777  switch (t->behavior)
778  {
779  case SR_BEHAVIOR_END:
780  s = format (s, "\tBehavior: End\n");
781  break;
782  case SR_BEHAVIOR_END_UN:
783  s = format (s, "\tBehavior: End.uN (flex)\n");
784  break;
786  s = format (s, "\tBehavior: End.uN\n");
787  break;
788  case SR_BEHAVIOR_DX6:
789  s = format (s, "\tBehavior: Decapsulation with IPv6 L3 xconnect\n");
790  break;
791  case SR_BEHAVIOR_DX4:
792  s = format (s, "\tBehavior: Decapsulation with IPv4 L3 xconnect\n");
793  break;
794  case SR_BEHAVIOR_X:
795  s = format (s, "\tBehavior: IPv6 L3 xconnect\n");
796  break;
797  case SR_BEHAVIOR_T:
798  s = format (s, "\tBehavior: IPv6 specific table lookup\n");
799  break;
800  case SR_BEHAVIOR_DT6:
801  s = format (s, "\tBehavior: Decapsulation with IPv6 Table lookup\n");
802  break;
803  case SR_BEHAVIOR_DT4:
804  s = format (s, "\tBehavior: Decapsulation with IPv4 Table lookup\n");
805  break;
806  case SR_BEHAVIOR_DX2:
807  s = format (s, "\tBehavior: Decapsulation with L2 xconnect\n");
808  break;
809  default:
810  s = format (s, "\tBehavior: defined in plugin\n"); //TODO
811  break;
812  }
813  if (t->num_segments != 0xFF)
814  {
815  if (t->num_segments > 0)
816  {
817  s = format (s, "\tSegments left: %d\n", t->segments_left);
818  s = format (s, "\tSID list: [in ietf order]");
819  int i = 0;
820  for (i = 0; i < t->num_segments; i++)
821  {
822  s = format (s, "\n\t-> %U", format_ip6_address,
823  (ip6_address_t *) & t->sr[i *
824  sizeof (ip6_address_t)]);
825  }
826  }
827  }
828  return s;
829 }
830 
831 /**
832  * @brief Function doing End processing.
833  */
836  vlib_buffer_t * b0,
837  ip6_header_t * ip0,
838  ip6_sr_header_t * sr0,
839  ip6_sr_localsid_t * ls0,
840  u32 * next0, u8 psp, ip6_ext_header_t * prev0)
841 {
842  ip6_address_t *new_dst0;
843 
844  if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
845  {
846  if (sr0->segments_left == 1 && psp)
847  {
848  u32 new_l0, sr_len;
849  u64 *copy_dst0, *copy_src0;
850  u32 copy_len_u64s0 = 0;
851 
852  ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
853  ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
854 
855  /* Remove the SRH taking care of the rest of IPv6 ext header */
856  if (prev0)
857  prev0->next_hdr = sr0->protocol;
858  else
859  ip0->protocol = sr0->protocol;
860 
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
870  * SR header
871  */
872  copy_len_u64s0 =
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];
879 
880  int i;
881  for (i = copy_len_u64s0 - 1; i >= 0; i--)
882  {
883  copy_dst0[i] = copy_src0[i];
884  }
885 
886  if (ls0->behavior == SR_BEHAVIOR_X)
887  {
888  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
889  *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
890  }
891  else if (ls0->behavior == SR_BEHAVIOR_T)
892  {
893  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
894  }
895  }
896  else if (PREDICT_TRUE (sr0->segments_left > 0))
897  {
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];
903 
904  if (ls0->behavior == SR_BEHAVIOR_X)
905  {
906  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
907  *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
908  }
909  else if (ls0->behavior == SR_BEHAVIOR_T)
910  {
911  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
912  }
913  }
914  else
915  {
916  *next0 = SR_LOCALSID_NEXT_ERROR;
917  b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
918  }
919  }
920  else
921  {
922  /* Error. Routing header of type != SR */
923  *next0 = SR_LOCALSID_NEXT_ERROR;
924  b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
925  }
926 }
927 
928 /**
929  * @brief Function doing End uN processing.
930  */
933  vlib_buffer_t * b0,
934  ip6_header_t * ip0,
935  ip6_sr_header_t * sr0,
936  ip6_sr_localsid_t * ls0,
937  u32 * next0, u8 psp, ip6_ext_header_t * prev0)
938 {
939  ip6_address_t *new_dst0;
940  bool next_usid = false;
941  u8 next_usid_index;
942  u8 usid_len;
943  u8 index;
944 
945  usid_len = ls0->usid_len;
946  next_usid_index = ls0->usid_next_index;
947 
948  /* uSID */
949  for (index = 0; index < usid_len; index++)
950  {
951  if (ip0->dst_address.as_u8[next_usid_index + index] != 0)
952  {
953  next_usid = true;
954  break;
955  }
956  }
957 
958  if (PREDICT_TRUE (next_usid))
959  {
960  u8 offset;
961 
962  index = ls0->usid_index;
963 
964  /* advance next usid */
965  for (offset = 0; offset < ls0->usid_next_len; offset++)
966  {
967  ip0->dst_address.as_u8[index + offset] =
968  ip0->dst_address.as_u8[next_usid_index + offset];
969  }
970 
971  for (index = 16 - usid_len; index < 16; index++)
972  {
973  ip0->dst_address.as_u8[index] = 0;
974  }
975 
976  return;
977  }
978 
979  if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
980  {
981  if (sr0->segments_left == 1 && psp)
982  {
983  u32 new_l0, sr_len;
984  u64 *copy_dst0, *copy_src0;
985  u32 copy_len_u64s0 = 0;
986 
987  ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
988  ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
989 
990  /* Remove the SRH taking care of the rest of IPv6 ext header */
991  if (prev0)
992  prev0->next_hdr = sr0->protocol;
993  else
994  ip0->protocol = sr0->protocol;
995 
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
1005  * SR header
1006  */
1007  copy_len_u64s0 =
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];
1014 
1015  int i;
1016  for (i = copy_len_u64s0 - 1; i >= 0; i--)
1017  {
1018  copy_dst0[i] = copy_src0[i];
1019  }
1020  }
1021  else if (PREDICT_TRUE (sr0->segments_left > 0))
1022  {
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];
1028  }
1029  else
1030  {
1031  *next0 = SR_LOCALSID_NEXT_ERROR;
1032  b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
1033  }
1034  }
1035  else
1036  {
1037  /* Error. Routing header of type != SR */
1038  *next0 = SR_LOCALSID_NEXT_ERROR;
1039  b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
1040  }
1041 }
1042 
1045 {
1046  u8 next_usid_index;
1047  u8 index;
1048  u8 offset;
1049 
1050  /* uSID */
1051  index = ls0->usid_index;
1052  next_usid_index = ls0->usid_next_index;
1053 
1054  /* advance next usid */
1055  for (offset = 0; offset < ls0->usid_next_len; offset++)
1056  {
1057  ip0->dst_address.as_u8[index + offset] =
1058  ip0->dst_address.as_u8[next_usid_index + offset];
1059  }
1060 
1061  for (index = 16 - ls0->usid_len; index < 16; index++)
1062  {
1063  ip0->dst_address.as_u8[index] = 0;
1064  }
1065 
1066  return;
1067 }
1068 
1069 /*
1070  * @brief Function doing SRH processing for D* variants
1071  */
1074  vlib_buffer_t * b0,
1075  ip6_header_t * ip0,
1076  ip6_sr_header_t * sr0,
1077  ip6_sr_localsid_t * ls0, u32 * next0)
1078 {
1079  /* Compute the size of the IPv6 header with all Ext. headers */
1080  u8 next_proto;
1081  ip6_ext_header_t *next_ext_header;
1082  u16 total_size = 0;
1083 
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))
1088  {
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);
1092  }
1093 
1094  /* Ensure this is the last segment. Otherwise drop. */
1095  if (sr0 && sr0->segments_left != 0)
1096  {
1097  *next0 = SR_LOCALSID_NEXT_ERROR;
1098  b0->error = node->errors[SR_LOCALSID_ERROR_NOT_LS];
1099  return;
1100  }
1101 
1102  switch (next_proto)
1103  {
1104  case IP_PROTOCOL_IPV6:
1105  /* Encap-End IPv6. Pop outer IPv6 header. */
1106  if (ls0->behavior == SR_BEHAVIOR_DX6)
1107  {
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;
1111  return;
1112  }
1113  else if (ls0->behavior == SR_BEHAVIOR_DT6)
1114  {
1115  vlib_buffer_advance (b0, total_size);
1116  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1117  return;
1118  }
1119  break;
1120  case IP_PROTOCOL_IP_IN_IP:
1121  /* Encap-End IPv4. Pop outer IPv6 header */
1122  if (ls0->behavior == SR_BEHAVIOR_DX4)
1123  {
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;
1127  return;
1128  }
1129  else if (ls0->behavior == SR_BEHAVIOR_DT4)
1130  {
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;
1134  return;
1135  }
1136  break;
1138  /* L2 encaps */
1139  if (ls0->behavior == SR_BEHAVIOR_DX2)
1140  {
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;
1144  return;
1145  }
1146  break;
1147  }
1148  *next0 = SR_LOCALSID_NEXT_ERROR;
1149  b0->error = node->errors[SR_LOCALSID_ERROR_NO_INNER_HEADER];
1150  return;
1151 }
1152 
1153 /**
1154  * @brief SR LocalSID graph node. Supports all default SR Endpoint variants with decaps
1155  */
1156 static uword
1158  vlib_frame_t * from_frame)
1159 {
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;
1166 
1167  while (n_left_from > 0)
1168  {
1169  u32 n_left_to_next;
1170  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1171 
1172  /* Quad - Loop */
1173  while (n_left_from >= 8 && n_left_to_next >= 4)
1174  {
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;
1182 
1183  /* Prefetch next iteration. */
1184  {
1185  vlib_buffer_t *p4, *p5, *p6, *p7;
1186 
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]);
1191 
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);
1197 
1202  }
1203 
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];
1208  from += 4;
1209  to_next += 4;
1210  n_left_from -= 4;
1211  n_left_to_next -= 4;
1212 
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);
1217 
1218  ls0 =
1220  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1221  ls1 =
1223  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1224  ls2 =
1226  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1227  ls3 =
1229  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1230 
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);
1235 
1236  sr0 =
1237  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1238  sr1 =
1239  ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, NULL);
1240  sr2 =
1241  ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, NULL);
1242  sr3 =
1243  ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, NULL);
1244 
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);
1249 
1250  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1251  {
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))
1259  {
1260  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1261  && sr0->type == ROUTING_HEADER_TYPE_SR)
1262  {
1263  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1264  tr->num_segments =
1265  sr0->length * 8 / sizeof (ip6_address_t);
1266  tr->segments_left = sr0->segments_left;
1267  }
1268  }
1269  else
1270  tr->num_segments = 0xFF;
1271  }
1272 
1273  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1274  {
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))
1282  {
1283  if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1284  && sr1->type == ROUTING_HEADER_TYPE_SR)
1285  {
1286  clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1287  tr->num_segments =
1288  sr1->length * 8 / sizeof (ip6_address_t);
1289  tr->segments_left = sr1->segments_left;
1290  }
1291  }
1292  else
1293  tr->num_segments = 0xFF;
1294  }
1295 
1296  if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1297  {
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))
1305  {
1306  if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1307  && sr2->type == ROUTING_HEADER_TYPE_SR)
1308  {
1309  clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1310  tr->num_segments =
1311  sr2->length * 8 / sizeof (ip6_address_t);
1312  tr->segments_left = sr2->segments_left;
1313  }
1314  }
1315  else
1316  tr->num_segments = 0xFF;
1317  }
1318 
1319  if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1320  {
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))
1328  {
1329  if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1330  && sr3->type == ROUTING_HEADER_TYPE_SR)
1331  {
1332  clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1333  tr->num_segments =
1334  sr3->length * 8 / sizeof (ip6_address_t);
1335  tr->segments_left = sr3->segments_left;
1336  }
1337  }
1338  else
1339  tr->num_segments = 0xFF;
1340  }
1341 
1343  (((next0 ==
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));
1347 
1349  (((next1 ==
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));
1353 
1355  (((next2 ==
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));
1359 
1361  (((next3 ==
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));
1365 
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);
1369  }
1370 
1371  /* Single loop for potentially the last three packets */
1372  while (n_left_from > 0 && n_left_to_next > 0)
1373  {
1374  u32 bi0;
1375  vlib_buffer_t *b0;
1376  ip6_header_t *ip0;
1377  ip6_sr_header_t *sr0;
1378  u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1379  ip6_sr_localsid_t *ls0;
1380 
1381  bi0 = from[0];
1382  to_next[0] = bi0;
1383  from += 1;
1384  to_next += 1;
1385  n_left_from -= 1;
1386  n_left_to_next -= 1;
1387 
1388  b0 = vlib_get_buffer (vm, bi0);
1389  ip0 = vlib_buffer_get_current (b0);
1390 
1391  /* Lookup the SR End behavior based on IP DA (adj) */
1392  ls0 =
1394  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1395 
1396  /* Find SRH as well as previous header */
1397  sr0 =
1398  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1399 
1400  /* SRH processing and End variants */
1401  end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1402 
1403  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1404  {
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))
1412  {
1413  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1414  && sr0->type == ROUTING_HEADER_TYPE_SR)
1415  {
1416  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1417  tr->num_segments =
1418  sr0->length * 8 / sizeof (ip6_address_t);
1419  tr->segments_left = sr0->segments_left;
1420  }
1421  }
1422  else
1423  tr->num_segments = 0xFF;
1424  }
1425 
1426  /* Increase the counters */
1428  (((next0 ==
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));
1432 
1433  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1434  n_left_to_next, bi0, next0);
1435  }
1436  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1437  }
1438  return from_frame->n_vectors;
1439 }
1440 
1441 /* *INDENT-OFF* */
1443  .function = sr_localsid_d_fn,
1444  .name = "sr-localsid-d",
1445  .vector_size = sizeof (u32),
1446  .format_trace = format_sr_localsid_trace,
1448  .n_errors = SR_LOCALSID_N_ERROR,
1449  .error_strings = sr_localsid_error_strings,
1450  .n_next_nodes = SR_LOCALSID_N_NEXT,
1451  .next_nodes = {
1452 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1454 #undef _
1455  },
1456 };
1457 /* *INDENT-ON* */
1458 
1459 /**
1460  * @brief SR LocalSID graph node. Supports all default SR Endpoint without decaps
1461  */
1462 static uword
1464  vlib_frame_t * from_frame)
1465 {
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;
1472 
1473  while (n_left_from > 0)
1474  {
1475  u32 n_left_to_next;
1476  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1477 
1478  /* Quad - Loop */
1479  while (n_left_from >= 8 && n_left_to_next >= 4)
1480  {
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;
1489 
1490  /* Prefetch next iteration. */
1491  {
1492  vlib_buffer_t *p4, *p5, *p6, *p7;
1493 
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]);
1498 
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);
1504 
1509  }
1510 
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];
1515  from += 4;
1516  to_next += 4;
1517  n_left_from -= 4;
1518  n_left_to_next -= 4;
1519 
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);
1524 
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);
1529 
1530  sr0 =
1531  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1532  sr1 =
1533  ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1534  sr2 =
1535  ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1536  sr3 =
1537  ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1538 
1539  ls0 =
1541  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1542  ls1 =
1544  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1545  ls2 =
1547  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1548  ls3 =
1550  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1551 
1552  end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1553  prev0);
1554  end_srh_processing (node, b1, ip1, sr1, ls1, &next1, ls1->end_psp,
1555  prev1);
1556  end_srh_processing (node, b2, ip2, sr2, ls2, &next2, ls2->end_psp,
1557  prev2);
1558  end_srh_processing (node, b3, ip3, sr3, ls3, &next3, ls3->end_psp,
1559  prev3);
1560 
1561  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1562  {
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))
1570  {
1571  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1572  && sr0->type == ROUTING_HEADER_TYPE_SR)
1573  {
1574  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1575  tr->num_segments =
1576  sr0->length * 8 / sizeof (ip6_address_t);
1577  tr->segments_left = sr0->segments_left;
1578  }
1579  }
1580  else
1581  tr->num_segments = 0xFF;
1582  }
1583 
1584  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1585  {
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))
1593  {
1594  if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1595  && sr1->type == ROUTING_HEADER_TYPE_SR)
1596  {
1597  clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1598  tr->num_segments =
1599  sr1->length * 8 / sizeof (ip6_address_t);
1600  tr->segments_left = sr1->segments_left;
1601  }
1602  }
1603  else
1604  tr->num_segments = 0xFF;
1605  }
1606 
1607  if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1608  {
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))
1616  {
1617  if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1618  && sr2->type == ROUTING_HEADER_TYPE_SR)
1619  {
1620  clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1621  tr->num_segments =
1622  sr2->length * 8 / sizeof (ip6_address_t);
1623  tr->segments_left = sr2->segments_left;
1624  }
1625  }
1626  else
1627  tr->num_segments = 0xFF;
1628  }
1629 
1630  if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1631  {
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))
1639  {
1640  if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1641  && sr3->type == ROUTING_HEADER_TYPE_SR)
1642  {
1643  clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1644  tr->num_segments =
1645  sr3->length * 8 / sizeof (ip6_address_t);
1646  tr->segments_left = sr3->segments_left;
1647  }
1648  }
1649  else
1650  tr->num_segments = 0xFF;
1651  }
1652 
1654  (((next0 ==
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));
1658 
1660  (((next1 ==
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));
1664 
1666  (((next2 ==
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));
1670 
1672  (((next3 ==
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));
1676 
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);
1680  }
1681 
1682  /* Single loop for potentially the last three packets */
1683  while (n_left_from > 0 && n_left_to_next > 0)
1684  {
1685  u32 bi0;
1686  vlib_buffer_t *b0;
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;
1692 
1693  bi0 = from[0];
1694  to_next[0] = bi0;
1695  from += 1;
1696  to_next += 1;
1697  n_left_from -= 1;
1698  n_left_to_next -= 1;
1699 
1700  b0 = vlib_get_buffer (vm, bi0);
1701  ip0 = vlib_buffer_get_current (b0);
1702  sr0 =
1703  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1704 
1705  /* Lookup the SR End behavior based on IP DA (adj) */
1706  ls0 =
1708  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1709 
1710  /* SRH processing */
1711  end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1712  prev0);
1713 
1714  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1715  {
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))
1723  {
1724  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1725  && sr0->type == ROUTING_HEADER_TYPE_SR)
1726  {
1727  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1728  tr->num_segments =
1729  sr0->length * 8 / sizeof (ip6_address_t);
1730  tr->segments_left = sr0->segments_left;
1731  }
1732  }
1733  else
1734  tr->num_segments = 0xFF;
1735  }
1736 
1738  (((next0 ==
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));
1742 
1743  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1744  n_left_to_next, bi0, next0);
1745  }
1746  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1747  }
1748  return from_frame->n_vectors;
1749 }
1750 
1751 /* *INDENT-OFF* */
1753  .function = sr_localsid_fn,
1754  .name = "sr-localsid",
1755  .vector_size = sizeof (u32),
1756  .format_trace = format_sr_localsid_trace,
1758  .n_errors = SR_LOCALSID_N_ERROR,
1759  .error_strings = sr_localsid_error_strings,
1760  .n_next_nodes = SR_LOCALSID_N_NEXT,
1761  .next_nodes = {
1762 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1764 #undef _
1765  },
1766 };
1767 /* *INDENT-ON* */
1768 
1769 /**
1770  * @brief SR LocalSID uN graph node. Supports all default SR Endpoint without decaps
1771  */
1772 static uword
1774  vlib_frame_t * from_frame)
1775 {
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;
1782 
1783  while (n_left_from > 0)
1784  {
1785  u32 n_left_to_next;
1786  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1787 
1788  /* Quad - Loop */
1789  while (n_left_from >= 8 && n_left_to_next >= 4)
1790  {
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;
1799 
1800  /* Prefetch next iteration. */
1801  {
1802  vlib_buffer_t *p4, *p5, *p6, *p7;
1803 
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]);
1808 
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);
1814 
1819  }
1820 
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];
1825  from += 4;
1826  to_next += 4;
1827  n_left_from -= 4;
1828  n_left_to_next -= 4;
1829 
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);
1834 
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);
1839 
1840  sr0 =
1841  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1842  sr1 =
1843  ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1844  sr2 =
1845  ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1846  sr3 =
1847  ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1848 
1849  ls0 =
1851  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1852  ls1 =
1854  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1855  ls2 =
1857  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1858  ls3 =
1860  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1861 
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);
1870 
1871  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1872  {
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))
1880  {
1881  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1882  && sr0->type == ROUTING_HEADER_TYPE_SR)
1883  {
1884  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1885  tr->num_segments =
1886  sr0->length * 8 / sizeof (ip6_address_t);
1887  tr->segments_left = sr0->segments_left;
1888  }
1889  }
1890  else
1891  tr->num_segments = 0xFF;
1892  }
1893 
1894  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1895  {
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))
1903  {
1904  if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1905  && sr1->type == ROUTING_HEADER_TYPE_SR)
1906  {
1907  clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1908  tr->num_segments =
1909  sr1->length * 8 / sizeof (ip6_address_t);
1910  tr->segments_left = sr1->segments_left;
1911  }
1912  }
1913  else
1914  tr->num_segments = 0xFF;
1915  }
1916 
1917  if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1918  {
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))
1926  {
1927  if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1928  && sr2->type == ROUTING_HEADER_TYPE_SR)
1929  {
1930  clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1931  tr->num_segments =
1932  sr2->length * 8 / sizeof (ip6_address_t);
1933  tr->segments_left = sr2->segments_left;
1934  }
1935  }
1936  else
1937  tr->num_segments = 0xFF;
1938  }
1939 
1940  if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1941  {
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))
1949  {
1950  if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1951  && sr3->type == ROUTING_HEADER_TYPE_SR)
1952  {
1953  clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1954  tr->num_segments =
1955  sr3->length * 8 / sizeof (ip6_address_t);
1956  tr->segments_left = sr3->segments_left;
1957  }
1958  }
1959  else
1960  tr->num_segments = 0xFF;
1961  }
1962 
1964  (((next0 ==
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));
1968 
1970  (((next1 ==
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));
1974 
1976  (((next2 ==
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));
1980 
1982  (((next3 ==
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));
1986 
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);
1990  }
1991 
1992  /* Single loop for potentially the last three packets */
1993  while (n_left_from > 0 && n_left_to_next > 0)
1994  {
1995  u32 bi0;
1996  vlib_buffer_t *b0;
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;
2002 
2003  bi0 = from[0];
2004  to_next[0] = bi0;
2005  from += 1;
2006  to_next += 1;
2007  n_left_from -= 1;
2008  n_left_to_next -= 1;
2009 
2010  b0 = vlib_get_buffer (vm, bi0);
2011  ip0 = vlib_buffer_get_current (b0);
2012  sr0 =
2013  ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
2014 
2015  /* Lookup the SR End behavior based on IP DA (adj) */
2016  ls0 =
2018  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2019 
2020  /* SRH processing */
2021  end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
2022  ls0->end_psp, prev0);
2023 
2024  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2025  {
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))
2033  {
2034  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
2035  && sr0->type == ROUTING_HEADER_TYPE_SR)
2036  {
2037  clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
2038  tr->num_segments =
2039  sr0->length * 8 / sizeof (ip6_address_t);
2040  tr->segments_left = sr0->segments_left;
2041  }
2042  }
2043  else
2044  tr->num_segments = 0xFF;
2045  }
2046 
2048  (((next0 ==
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));
2052 
2053  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2054  n_left_to_next, bi0, next0);
2055  }
2056  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2057  }
2058  return from_frame->n_vectors;
2059 }
2060 
2061 /* *INDENT-OFF* */
2063  .function = sr_localsid_un_fn,
2064  .name = "sr-localsid-un",
2065  .vector_size = sizeof (u32),
2066  .format_trace = format_sr_localsid_trace,
2068  .n_errors = SR_LOCALSID_N_ERROR,
2069  .error_strings = sr_localsid_error_strings,
2070  .n_next_nodes = SR_LOCALSID_N_NEXT,
2071  .next_nodes = {
2072 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2074 #undef _
2075  },
2076 };
2077 /* *INDENT-ON* */
2078 
2079 static uword
2081  vlib_frame_t * from_frame)
2082 {
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;
2089 
2090  while (n_left_from > 0)
2091  {
2092  u32 n_left_to_next;
2093  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2094 
2095  /* Quad - Loop */
2096  while (n_left_from >= 8 && n_left_to_next >= 4)
2097  {
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;
2104 
2105  /* Prefetch next iteration. */
2106  {
2107  vlib_buffer_t *p4, *p5, *p6, *p7;
2108 
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]);
2113 
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);
2119 
2124  }
2125 
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];
2130  from += 4;
2131  to_next += 4;
2132  n_left_from -= 4;
2133  n_left_to_next -= 4;
2134 
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);
2139 
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);
2144 
2145  ls0 =
2147  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2148  ls1 =
2150  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2151  ls2 =
2153  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2154  ls3 =
2156  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2157 
2158  end_un_processing (ip0, ls0);
2159  end_un_processing (ip1, ls1);
2160  end_un_processing (ip2, ls2);
2161  end_un_processing (ip3, ls3);
2162 
2163  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2164  {
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;
2171  }
2172 
2173  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2174  {
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;
2181  }
2182 
2183  if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2184  {
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;
2191  }
2192 
2193  if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2194  {
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;
2201  }
2202 
2204  (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2205  1, vlib_buffer_length_in_chain (vm, b0));
2206 
2208  (&(sm->sr_ls_valid_counters), thread_index, ls1 - sm->localsids,
2209  1, vlib_buffer_length_in_chain (vm, b1));
2210 
2212  (&(sm->sr_ls_valid_counters), thread_index, ls2 - sm->localsids,
2213  1, vlib_buffer_length_in_chain (vm, b2));
2214 
2216  (&(sm->sr_ls_valid_counters), thread_index, ls3 - sm->localsids,
2217  1, vlib_buffer_length_in_chain (vm, b3));
2218 
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);
2222  }
2223 
2224  /* Single loop for potentially the last three packets */
2225  while (n_left_from > 0 && n_left_to_next > 0)
2226  {
2227  u32 bi0;
2228  vlib_buffer_t *b0;
2229  ip6_header_t *ip0 = 0;
2230  u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2231  ip6_sr_localsid_t *ls0;
2232 
2233  bi0 = from[0];
2234  to_next[0] = bi0;
2235  from += 1;
2236  to_next += 1;
2237  n_left_from -= 1;
2238  n_left_to_next -= 1;
2239 
2240  b0 = vlib_get_buffer (vm, bi0);
2241  ip0 = vlib_buffer_get_current (b0);
2242 
2243  /* Lookup the SR End behavior based on IP DA (adj) */
2244  ls0 =
2246  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2247 
2248  /* SRH processing */
2249  end_un_processing (ip0, ls0);
2250 
2251  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2252  {
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;
2259  }
2260 
2262  (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2263  1, vlib_buffer_length_in_chain (vm, b0));
2264 
2265  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2266  n_left_to_next, bi0, next0);
2267  }
2268  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2269  }
2270  return from_frame->n_vectors;
2271 }
2272 
2273 /* *INDENT-OFF* */
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,
2280  .n_errors = SR_LOCALSID_N_ERROR,
2281  .error_strings = sr_localsid_error_strings,
2282  .n_next_nodes = SR_LOCALSID_N_NEXT,
2283  .next_nodes = {
2284 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2286 #undef _
2287  },
2288 };
2289 /* *INDENT-ON* */
2290 
2291 static u8 *
2292 format_sr_dpo (u8 * s, va_list * args)
2293 {
2294  index_t index = va_arg (*args, index_t);
2295  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
2296 
2297  return (format (s, "SR: localsid_index:[%d]", index));
2298 }
2299 
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,
2304 };
2305 
2306 const static char *const sr_loc_ip6_nodes[] = {
2307  "sr-localsid",
2308  NULL,
2309 };
2310 
2311 const static char *const *const sr_loc_nodes[DPO_PROTO_NUM] = {
2313 };
2314 
2315 const static char *const sr_loc_d_ip6_nodes[] = {
2316  "sr-localsid-d",
2317  NULL,
2318 };
2319 
2320 const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
2322 };
2323 
2324 const static char *const sr_loc_un_ip6_nodes[] = {
2325  "sr-localsid-un",
2326  NULL,
2327 };
2328 
2329 const static char *const *const sr_loc_un_nodes[DPO_PROTO_NUM] = {
2331 };
2332 
2333 const static char *const sr_loc_un_perf_ip6_nodes[] = {
2334  "sr-localsid-un-perf",
2335  NULL,
2336 };
2337 
2338 const static char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM] = {
2340 };
2341 
2342 /*************************** SR LocalSID plugins ******************************/
2343 /**
2344  * @brief SR LocalSID plugin registry
2345  */
2346 int
2348  u8 * keyword_str, u8 * def_str,
2349  u8 * params_str, u8 prefix_length,
2350  dpo_type_t * dpo,
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)
2355 {
2356  ip6_sr_main_t *sm = &sr_main;
2357  uword *p;
2358 
2360 
2361  /* Did this function exist? If so update it */
2362  p = hash_get_mem (sm->plugin_functions_by_key, fn_name);
2363  if (p)
2364  {
2365  plugin = pool_elt_at_index (sm->plugin_functions, p[0]);
2366  }
2367  /* Else create a new one and set hash key */
2368  else
2369  {
2370  pool_get (sm->plugin_functions, plugin);
2371  hash_set_mem (sm->plugin_functions_by_key, fn_name,
2372  plugin - sm->plugin_functions);
2373  }
2374 
2375  clib_memset (plugin, 0, sizeof (*plugin));
2376 
2377  plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
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);
2389 
2390  return plugin->sr_localsid_function_number;
2391 }
2392 
2393 /**
2394  * @brief CLI function to 'show' all available SR LocalSID behaviors
2395  */
2396 static clib_error_t *
2398  unformat_input_t * input,
2399  vlib_cli_command_t * cmd)
2400 {
2401  ip6_sr_main_t *sm = &sr_main;
2403  sr_localsid_fn_registration_t **plugins_vec = 0;
2404  int i;
2405 
2406  vlib_cli_output (vm,
2407  "SR LocalSIDs behaviors:\n-----------------------\n\n");
2408 
2409  /* *INDENT-OFF* */
2410  pool_foreach (plugin, sm->plugin_functions)
2411  { vec_add1 (plugins_vec, plugin); }
2412  /* *INDENT-ON* */
2413 
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++)
2433  {
2434  plugin = plugins_vec[i];
2435  vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
2436  plugin->def_str);
2437  vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
2438  }
2439  return 0;
2440 }
2441 
2442 /* *INDENT-OFF* */
2443 VLIB_CLI_COMMAND (show_sr_localsid_behaviors_command, static) = {
2444  .path = "show sr localsids behaviors",
2445  .short_help = "show sr localsids behaviors",
2447 };
2448 /* *INDENT-ON* */
2449 
2450 /**
2451  * @brief SR LocalSID initialization
2452  */
2453 clib_error_t *
2455 {
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 */
2462  /* Init SR behaviors DPO type */
2464  dpo_register_new_type (&sr_loc_vft, sr_loc_d_nodes);
2465  /* Init SR bhaviors DPO type */
2467  dpo_register_new_type (&sr_loc_vft, sr_loc_un_nodes);
2470  /* Init memory for localsid plugins */
2471  sm->plugin_functions_by_key = hash_create_string (0, sizeof (uword));
2472  return 0;
2473 }
2474 
2476 /*
2477 * fd.io coding-style-patch-verification: ON
2478 *
2479 * Local Variables:
2480 * eval: (c-set-style "gnu")
2481 * End:
2482 */
u8 * function_name
Function name.
Definition: sr.h:165
#define SR_BEHAVIOR_D_FIRST
Definition: sr.h:40
sr_localsid_error_t
Definition: sr_localsid.c:732
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:211
ip6_sr_main_t sr_main
Definition: sr.c:31
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:411
u32 vlan_index
VLAN tag (not an index)
Definition: sr.h:138
static dpo_type_t sr_localsid_un_perf_dpo_type
Definition: sr_localsid.c:49
u32 nh_adj
Next_adj for xconnect usage only.
Definition: sr.h:142
#define CLIB_UNUSED(x)
Definition: clib.h:87
A virtual function table regisitered for a DPO type.
Definition: dpo.h:406
static const char *const sr_loc_ip6_nodes[]
Definition: sr_localsid.c:2306
#define IP_PROTOCOL_IP6_ETHERNET
Definition: mobile.h:37
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:108
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:97
#define SR_BEHAVIOR_X
Definition: sr.h:38
static_always_inline void end_un_srh_processing(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip6_sr_header_t *sr0, ip6_sr_localsid_t *ls0, u32 *next0, u8 psp, ip6_ext_header_t *prev0)
Function doing End uN processing.
Definition: sr_localsid.c:932
static const char *const sr_loc_un_perf_ip6_nodes[]
Definition: sr_localsid.c:2333
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:239
vlib_node_registration_t sr_localsid_un_perf_node
(constructor) VLIB_REGISTER_NODE (sr_localsid_un_perf_node)
Definition: sr_localsid.c:2274
SR LocalSID.
Definition: sr.h:120
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
#define PREDICT_TRUE(x)
Definition: clib.h:122
void sr_dpo_unlock(dpo_id_t *dpo)
no-op unlock function.
Definition: sr.c:47
unsigned long u64
Definition: types.h:89
#define SR_BEHAVIOR_END_UN_PERF
Definition: sr.h:46
unsigned char params_str[32]
#define SR_BEHAVIOR_END_UN
Definition: sr.h:47
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
format_function_t * ls_format
LocalSID format function.
Definition: sr.h:177
static const char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM]
Definition: sr_localsid.c:2338
ip6_address_t localsid
Definition: sr_localsid.c:717
u32 thread_index
Definition: main.h:250
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define SR_BEHAVIOR_DT6
Definition: sr.h:44
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
u8 usid_next_index
Definition: sr.h:150
static_always_inline void end_decaps_srh_processing(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip6_sr_header_t *sr0, ip6_sr_localsid_t *ls0, u32 *next0)
Definition: sr_localsid.c:1073
#define vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, next0, next1, next2, next3)
Finish enqueueing four buffers forward in the graph.
Definition: buffer_node.h:140
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
static void * ip6_ext_next_header(ip6_ext_header_t *ext_hdr)
Definition: ip6_packet.h:518
#define hash_set_mem(h, key, value)
Definition: hash.h:275
vlib_main_t * vm
Definition: in2out_ed.c:1578
u16 behavior
Behavior associated to this localsid.
Definition: sr.h:128
unformat_function_t unformat_vnet_sw_interface
#define ROUTING_HEADER_TYPE_SR
Definition: sr_packet.h:117
u16 localsid_prefix_len
Definition: sr.h:124
unsigned char keyword_str[32]
static const char *const *const sr_loc_un_nodes[DPO_PROTO_NUM]
Definition: sr_localsid.c:2329
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:402
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
vlib_combined_counter_main_t sr_ls_invalid_counters
Definition: sr.h:301
vlib_combined_counter_main_t sr_ls_valid_counters
Definition: sr.h:300
vhost_vring_addr_t addr
Definition: vhost_user.h:111
static char * sr_localsid_error_strings[]
Definition: sr_localsid.c:740
static clib_error_t * show_sr_localsid_behaviors_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI function to &#39;show&#39; all available SR LocalSID behaviors.
Definition: sr_localsid.c:2397
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
#define SR_BEHAVIOR_DT4
Definition: sr.h:45
static const char *const sr_loc_d_ip6_nodes[]
Definition: sr_localsid.c:2315
#define clib_memcpy(d, s, n)
Definition: string.h:180
u8 *() format_function_t(u8 *s, va_list *args)
Definition: format.h:48
static_always_inline void end_un_processing(ip6_header_t *ip0, ip6_sr_localsid_t *ls0)
Definition: sr_localsid.c:1044
static const char *const *const sr_loc_nodes[DPO_PROTO_NUM]
Definition: sr_localsid.c:2311
static void ip46_address_reset(ip46_address_t *ip46)
Definition: ip46_address.h:74
format_function_t format_ip4_address
Definition: format.h:73
#define static_always_inline
Definition: clib.h:109
static clib_error_t * sr_cli_localsid_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
SR LocalSID CLI function.
Definition: sr_localsid.c:325
void vlib_clear_combined_counters(vlib_combined_counter_main_t *cm)
Clear a collection of combined counters.
Definition: counter.c:61
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
unformat_function_t unformat_ip4_address
Definition: format.h:68
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define SR_BEHAVIOR_LAST
Definition: sr.h:48
description fragment has unexpected format
Definition: map.api:433
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:207
ip6_address_t address
Definition: sr.h:247
Aggregate type for a prefix.
Definition: fib_types.h:202
#define clib_error_return(e, args...)
Definition: error.h:99
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:347
static uword sr_localsid_un_perf_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: sr_localsid.c:2080
unsigned int u32
Definition: types.h:88
static const char *const sr_loc_un_ip6_nodes[]
Definition: sr_localsid.c:2324
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1106
u16 fp_len
The mask length.
Definition: fib_types.h:206
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:347
static void * ip6_ext_header_find(vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6_header, u8 header_type, ip6_ext_header_t **prev_ext_header)
Definition: ip6_packet.h:544
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static uword sr_localsid_un_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
SR LocalSID uN graph node.
Definition: sr_localsid.c:1773
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
Definition: fib_entry.h:116
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:546
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread counters.
Definition: counter.h:304
counter_t packets
packet counter
Definition: counter_types.h:28
vlib_node_registration_t sr_localsid_d_node
(constructor) VLIB_REGISTER_NODE (sr_localsid_d_node)
Definition: sr_localsid.c:1442
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:225
vl_api_address_t nh_addr
Definition: lisp_gpe.api:222
#define SR_BEHAVIOR_END
Definition: sr.h:37
u8 * format_sr_localsid_trace(u8 *s, va_list *args)
SR LocalSID graph node trace function.
Definition: sr_localsid.c:768
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
SR LocalSID behavior registration.
Definition: sr.h:161
unsigned char def_str[64]
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
char end_psp
Combined with End.PSP?
Definition: sr.h:126
ip6_address_t usid_block_mask
Definition: sr.h:145
static dpo_type_t sr_localsid_d_dpo_type
Definition: sr_localsid.c:47
#define PREDICT_FALSE(x)
Definition: clib.h:121
void sr_dpo_lock(dpo_id_t *dpo)
no-op lock function.
Definition: sr.c:38
static u8 * format_sr_dpo(u8 *s, va_list *args)
Definition: sr_localsid.c:2292
static_always_inline void end_srh_processing(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip6_sr_header_t *sr0, ip6_sr_localsid_t *ls0, u32 *next0, u8 psp, ip6_ext_header_t *prev0)
Function doing End processing.
Definition: sr_localsid.c:835
#define SR_BEHAVIOR_DX4
Definition: sr.h:43
uword() unformat_function_t(unformat_input_t *input, va_list *args)
Definition: format.h:232
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:391
int sr_cli_localsid(char is_del, ip6_address_t *localsid_addr, u16 localsid_prefix_len, char end_psp, u8 behavior, u32 sw_if_index, u32 vlan_index, u32 fib_table, ip46_address_t *nh_addr, int usid_len, void *ls_plugin_mem)
SR localsid add/del.
Definition: sr_localsid.c:77
__clib_export void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
static uword sr_localsid_d_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
SR LocalSID graph node.
Definition: sr_localsid.c:1157
#define ip6_ext_header_len(p)
Definition: ip6_packet.h:514
static u8 fn_name[]
Definition: gtp4_d.c:66
unformat_function_t unformat_ip6_address
Definition: format.h:89
ip6_sr_localsid_t * localsids
Definition: sr.h:270
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
u8 usid_index
Definition: sr.h:147
ip6_address_t usid_block
Definition: sr.h:144
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static clib_error_t * show_sr_localsid_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI function to &#39;show&#39; all SR LocalSIDs on console.
Definition: sr_localsid.c:543
SRv6 and SR-MPLS.
Definition: fib_source.h:60
u16 n_vectors
Definition: node.h:397
format_function_t format_ip6_address
Definition: format.h:91
int() sr_plugin_callback_t(ip6_sr_localsid_t *localsid)
Definition: sr.h:156
static void vlib_get_combined_counter(const vlib_combined_counter_main_t *cm, u32 index, vlib_counter_t *result)
Get the value of a combined counter, never called in the speed path Scrapes the entire set of per-thr...
Definition: counter.h:278
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
static clib_error_t * clear_sr_localsid_counters_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Function to &#39;clear&#39; ALL SR localsid counters.
Definition: sr_localsid.c:691
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:895
u8 data[]
Packet data.
Definition: buffer.h:181
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
unformat_function_t * ls_unformat
LocalSID unformat function.
Definition: sr.h:179
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:186
static u8 ip6_ext_hdr(u8 nexthdr)
Definition: ip6_packet.h:493
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1578
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:324
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:511
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
dpo_type_t dpo
DPO type registration.
Definition: sr.h:175
u8 * def_str
Behavior definition (i.e.
Definition: sr.h:169
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
void * plugin_mem
Memory to be used by the plugin callback functions.
Definition: sr.h:153
u32 fib_table_get_table_id(u32 fib_index, fib_protocol_t proto)
Get the Table-ID of the FIB from protocol and index.
Definition: fib_table.c:1095
static const char *const *const sr_loc_d_nodes[DPO_PROTO_NUM]
Definition: sr_localsid.c:2320
u32 vrf_index
vrf only
Definition: sr.h:133
int sr_localsid_register_function(vlib_main_t *vm, u8 *fn_name, u8 *keyword_str, u8 *def_str, u8 *params_str, u8 prefix_length, dpo_type_t *dpo, format_function_t *ls_format, unformat_function_t *ls_unformat, sr_plugin_callback_t *creation_fn, sr_plugin_callback_t *removal_fn)
SR LocalSID plugin registry.
Definition: sr_localsid.c:2347
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:252
u16 pref_len
Definition: sr.h:248
u32 fib_table
FIB table where localsid is registered.
Definition: sr.h:136
#define SR_BEHAVIOR_DX2
Definition: sr.h:41
SR localsid node trace.
Definition: sr_localsid.c:715
u16 sr_localsid_function_number
SR LocalSID plugin function (>SR_BEHAVIOR_LAST)
Definition: sr.h:163
typedef key
Definition: ipsec_types.api:86
__clib_export uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
counter_t bytes
byte counter
Definition: counter_types.h:29
Definition: defs.h:47
u8 usid_next_len
Definition: sr.h:151
#define DPO_PROTO_NUM
Definition: dpo.h:70
u16 payload_length
Definition: ip6_packet.h:301
vl_api_address_t ip
Definition: l2.api:501
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
#define SR_BEHAVIOR_T
Definition: sr.h:39
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip6_address_t segments[0]
Definition: sr_packet.h:149
sr_plugin_callback_t * creation
Function within plugin that will be called after localsid creation.
Definition: sr.h:181
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:202
u32 index
Definition: flow_types.api:221
clib_error_t * sr_localsids_init(vlib_main_t *vm)
SR LocalSID initialization.
Definition: sr_localsid.c:2454
#define hash_get_mem(h, key)
Definition: hash.h:269
struct clib_bihash_value offset
template key/value backing page structure
static void ip6_address_mask_from_width(ip6_address_t *a, u32 width)
Definition: ip6_packet.h:211
#define vnet_buffer(b)
Definition: buffer.h:417
vlib_node_registration_t sr_localsid_node
(constructor) VLIB_REGISTER_NODE (sr_localsid_node)
Definition: sr_localsid.c:1752
Segment Routing data structures definitions.
Segment Routing main datastructure.
Definition: sr.h:255
vlib_node_registration_t sr_localsid_un_node
(constructor) VLIB_REGISTER_NODE (sr_localsid_un_node)
Definition: sr_localsid.c:2062
adj_index_t adj_nbr_add_or_lock(fib_protocol_t nh_proto, vnet_link_t link_type, const ip46_address_t *nh_addr, u32 sw_if_index)
Neighbour Adjacency sub-type.
Definition: adj_nbr.c:236
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#define vec_foreach(var, vec)
Vector iterator.
static uword sr_localsid_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
SR LocalSID graph node.
Definition: sr_localsid.c:1463
#define foreach_sr_localsid_next
Definition: sr_localsid.c:746
static dpo_type_t sr_localsid_un_dpo_type
Definition: sr_localsid.c:48
ip46_address_t next_hop
Next_hop for xconnect usage only.
Definition: sr.h:140
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
mhash_t sr_localsids_index_hash
Definition: sr.h:273
u8 * params_str
Behavior parameters (i.e.
Definition: sr.h:171
#define foreach_sr_localsid_error
Definition: sr_localsid.c:724
static void sr_localsid_key_create(sr_localsid_key_t *key, ip6_address_t *addr, u16 pref_len)
Definition: sr_localsid.c:52
u32 sw_if_index
xconnect only
Definition: sr.h:132
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
sr_plugin_callback_t * removal
Function within plugin that will be called before localsid removal.
Definition: sr.h:183
ip6_address_t localsid
LocalSID IPv6 address.
Definition: sr.h:122
static dpo_type_t sr_localsid_dpo_type
Dynamically added SR localsid DPO type.
Definition: sr_localsid.c:46
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
u8 * keyword_str
Behavior keyword (i.e.
Definition: sr.h:167
sr_localsid_fn_registration_t * plugin_functions
Definition: sr.h:288
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
sr_localsid_next_t
Definition: sr_localsid.c:754
#define SR_BEHAVIOR_DX6
Definition: sr.h:42
ip6_address_t dst_address
Definition: ip6_packet.h:310
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
uword * plugin_functions_by_key
Definition: sr.h:291