vlib: improvement to automatic core pinning
[vpp.git] / src / vnet / srv6 / sr_localsid.c
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  */
46 static dpo_type_t sr_localsid_dpo_type;
47 static dpo_type_t sr_localsid_d_dpo_type;
48 static dpo_type_t sr_localsid_un_dpo_type;
49 static dpo_type_t sr_localsid_un_perf_dpo_type;
50
51 static void
52 sr_localsid_key_create (sr_localsid_key_t * key, ip6_address_t * addr,
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;
86   sr_localsid_fn_registration_t *plugin = 0;
87   sr_localsid_key_t key;
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 = {
117             .fp_proto = FIB_PROTOCOL_IP6,
118             .fp_len = pref_length,
119             .fp_addr = {
120                         .ip6 = *localsid_addr,
121                         }
122           };
123
124           fib_table_entry_delete (fib_table_find
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 =
156         pool_elt_at_index (sm->plugin_functions, behavior - SR_BEHAVIOR_LAST);
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 = {
167     .fp_proto = FIB_PROTOCOL_IP6,
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:
200     case SR_BEHAVIOR_END_UN_PERF:
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)
251         nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
252                                             nh_addr, sw_if_index);
253
254       else if (ls->behavior == SR_BEHAVIOR_DX4)
255         nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
256                                             nh_addr, sw_if_index);
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)
271     dpo_set (&dpo, sr_localsid_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
272   else if (ls->behavior == SR_BEHAVIOR_END_UN)
273     dpo_set (&dpo, sr_localsid_un_dpo_type, DPO_PROTO_IP6,
274              ls - sm->localsids);
275   else if (ls->behavior == SR_BEHAVIOR_END_UN_PERF)
276     dpo_set (&dpo, sr_localsid_un_perf_dpo_type, DPO_PROTO_IP6,
277              ls - sm->localsids);
278   else if (ls->behavior > SR_BEHAVIOR_D_FIRST
279            && ls->behavior < SR_BEHAVIOR_LAST)
280     dpo_set (&dpo, sr_localsid_d_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
281   else if (ls->behavior >= SR_BEHAVIOR_LAST)
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
301   fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR,
302                                    FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
303   dpo_reset (&dpo);
304
305   /* Set counter to zero */
306   vlib_validate_combined_counter (&(sm->sr_ls_valid_counters),
307                                   ls - sm->localsids);
308   vlib_validate_combined_counter (&(sm->sr_ls_invalid_counters),
309                                   ls - sm->localsids);
310
311   vlib_zero_combined_counter (&(sm->sr_ls_valid_counters),
312                               ls - sm->localsids);
313   vlib_zero_combined_counter (&(sm->sr_ls_invalid_counters),
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 *
325 sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
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
346   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
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               pool_foreach (plugin, sm->plugin_functions)
400                 {
401                   vec_add1 (vec_plugins, plugin);
402                 }
403
404               vec_foreach (plugin_it, vec_plugins)
405               {
406                 if (unformat
407                     (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
408                   {
409                     behavior = (*plugin_it)->sr_localsid_function_number;
410                     break;
411                   }
412               }
413             }
414
415           if (!behavior)
416             {
417               if (unformat (input, "end"))
418                 behavior = SR_BEHAVIOR_END;
419               else
420                 break;
421             }
422         }
423       else if (!end_psp && unformat (input, "psp"))
424         end_psp = 1;
425       else
426         break;
427     }
428
429   if (!behavior && end_psp)
430     behavior = SR_BEHAVIOR_END;
431
432   if (usid_size)
433     {
434       if (prefix_len < usid_size)
435         return clib_error_return (0,
436                                   "Error: Prefix length must be greater"
437                                   " than uSID length.");
438
439       if (usid_size != 16 && usid_size != 32)
440         return clib_error_return (0,
441                                   "Error: Invalid uSID length (16 or 32).");
442
443       if ((prefix_len - usid_size) & 0x7)
444         return clib_error_return (0,
445                                   "Error: Prefix Length must be multiple of 8.");
446     }
447
448   if (!address_set)
449     return clib_error_return (0,
450                               "Error: SRv6 LocalSID address is mandatory.");
451   if (!is_del && !behavior)
452     return clib_error_return (0,
453                               "Error: SRv6 LocalSID behavior is mandatory.");
454   if (vlan_index != (u32) ~ 0)
455     return clib_error_return (0,
456                               "Error: SRv6 End.DX2 with rewrite VLAN tag not supported by now.");
457   if (end_psp && !(behavior == SR_BEHAVIOR_END || behavior == SR_BEHAVIOR_X))
458     return clib_error_return (0,
459                               "Error: SRv6 PSP only compatible with End and End.X");
460
461   rv =
462     sr_cli_localsid (is_del, &resulting_address, prefix_len, end_psp,
463                      behavior, sw_if_index, vlan_index, fib_index, &next_hop,
464                      usid_size, ls_plugin_mem);
465
466   if (behavior == SR_BEHAVIOR_END_UN_PERF)
467     {
468       if (rv == 0)
469         {
470           u16 perf_len;
471           perf_len = prefix_len + usid_size;
472           rv = sr_cli_localsid (is_del, &resulting_address, perf_len, end_psp,
473                                 SR_BEHAVIOR_END, sw_if_index, vlan_index,
474                                 fib_index, &next_hop, 0, ls_plugin_mem);
475         }
476     }
477
478   switch (rv)
479     {
480     case 0:
481       break;
482     case 1:
483       return 0;
484     case -1:
485       return clib_error_return (0,
486                                 "Identical localsid already exists. Requested localsid not created.");
487     case -2:
488       return clib_error_return (0,
489                                 "The requested localsid could not be deleted. SR localsid not found");
490     case -3:
491       return clib_error_return (0, "FIB table %u does not exist", fib_index);
492     case -4:
493       return clib_error_return (0, "There is already one FIB entry for the"
494                                 "requested localsid non segment routing related");
495     case -5:
496       return clib_error_return (0,
497                                 "Could not create ARP/ND entry for such next_hop. Internal error.");
498     case -6:
499       return clib_error_return (0,
500                                 "Error on the plugin based localsid creation.");
501     default:
502       return clib_error_return (0, "BUG: sr localsid returns %d", rv);
503     }
504   return 0;
505 }
506
507 VLIB_CLI_COMMAND (sr_localsid_command, static) = {
508   .path = "sr localsid",
509   .short_help = "sr localsid (del) address XX:XX::YY:YY"
510       "(fib-table 8) behavior STRING",
511   .long_help =
512     "Create SR LocalSID and binds it to a particular behavior\n"
513     "Arguments:\n"
514     "\tlocalSID IPv6_addr(128b)   LocalSID IPv6 address\n"
515     "\t(fib-table X)              Optional. VRF where to install SRv6 localsid\n"
516     "\tbehavior STRING            Specifies the behavior\n"
517     "\n\tBehaviors:\n"
518     "\tEnd\t-> Endpoint.\n"
519     "\tEnd.uN\t-> Endpoint with uSID.\n"
520     "\tEnd.X\t-> Endpoint with decapsulation and Layer-3 cross-connect.\n"
521     "\t\tParameters: '<iface> <ip6_next_hop>'\n"
522     "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
523     "\t\tParameters: '<iface>'\n"
524     "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
525     "\t\tParameters: '<iface> <ip6_next_hop>'\n"
526     "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
527     "\t\tParameters: '<iface> <ip4_next_hop>'\n"
528     "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
529     "\t\tParameters: '<ip6_fib_table>'\n"
530     "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
531     "\t\tParameters: '<ip4_fib_table>'\n",
532   .function = sr_cli_localsid_command_fn,
533 };
534
535 /**
536  * @brief CLI function to 'show' all SR LocalSIDs on console.
537  */
538 static clib_error_t *
539 show_sr_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
540                              vlib_cli_command_t * cmd)
541 {
542   vnet_main_t *vnm = vnet_get_main ();
543   ip6_sr_main_t *sm = &sr_main;
544   ip6_sr_localsid_t **localsid_list = 0;
545   ip6_sr_localsid_t *ls;
546   int i;
547
548   vlib_cli_output (vm, "SRv6 - My LocalSID Table:");
549   vlib_cli_output (vm, "=========================");
550   pool_foreach (ls, sm->localsids)  { vec_add1 (localsid_list, ls); }
551   for (i = 0; i < vec_len (localsid_list); i++)
552     {
553       ls = localsid_list[i];
554       switch (ls->behavior)
555         {
556         case SR_BEHAVIOR_END:
557           vlib_cli_output (vm, "\tAddress: \t%U\n\tBehavior: \tEnd",
558                            format_ip6_address, &ls->localsid);
559           break;
560         case SR_BEHAVIOR_END_UN:
561           vlib_cli_output (vm,
562                            "\tAddress: \t%U\n\tBehavior: \tEnd (flex) [uSID:\t%U/%d, length: %d]",
563                            format_ip6_address, &ls->localsid,
564                            format_ip6_address, &ls->usid_block,
565                            ls->usid_index * 8, ls->usid_len * 8);
566           break;
567         case SR_BEHAVIOR_END_UN_PERF:
568           vlib_cli_output (vm,
569                            "\tAddress: \t%U\n\tBehavior: \tEnd [uSID:\t%U/%d, length: %d]",
570                            format_ip6_address, &ls->localsid,
571                            format_ip6_address, &ls->usid_block,
572                            ls->usid_index * 8, ls->usid_len * 8);
573           break;
574         case SR_BEHAVIOR_X:
575           vlib_cli_output (vm,
576                            "\tAddress: \t%U/%u\n\tBehavior: \tX (Endpoint with Layer-3 cross-connect)"
577                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
578                            format_ip6_address, &ls->localsid,
579                            ls->localsid_prefix_len,
580                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
581                            format_ip6_address, &ls->next_hop.ip6);
582           break;
583         case SR_BEHAVIOR_T:
584           vlib_cli_output (vm,
585                            "\tAddress: \t%U/%u\n\tBehavior: \tT (Endpoint with specific IPv6 table lookup)"
586                            "\n\tTable:  \t%u",
587                            format_ip6_address, &ls->localsid,
588                            ls->localsid_prefix_len,
589                            fib_table_get_table_id (ls->vrf_index,
590                                                    FIB_PROTOCOL_IP6));
591           break;
592         case SR_BEHAVIOR_DX4:
593           vlib_cli_output (vm,
594                            "\tAddress: \t%U/%u\n\tBehavior: \tDX4 (Endpoint with decapsulation and IPv4 cross-connect)"
595                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
596                            format_ip6_address, &ls->localsid,
597                            ls->localsid_prefix_len,
598                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
599                            format_ip4_address, &ls->next_hop.ip4);
600           break;
601         case SR_BEHAVIOR_DX6:
602           vlib_cli_output (vm,
603                            "\tAddress: \t%U/%u\n\tBehavior: \tDX6 (Endpoint with decapsulation and IPv6 cross-connect)"
604                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
605                            format_ip6_address, &ls->localsid,
606                            ls->localsid_prefix_len,
607                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
608                            format_ip6_address, &ls->next_hop.ip6);
609           break;
610         case SR_BEHAVIOR_DX2:
611           if (ls->vlan_index == (u32) ~ 0)
612             vlib_cli_output (vm,
613                              "\tAddress: \t%U/%u\n\tBehavior: \tDX2 (Endpoint with decapulation and Layer-2 cross-connect)"
614                              "\n\tIface:  \t%U", format_ip6_address,
615                              &ls->localsid, ls->localsid_prefix_len,
616                              format_vnet_sw_if_index_name, vnm,
617                              ls->sw_if_index);
618           else
619             vlib_cli_output (vm,
620                              "Unsupported yet. (DX2 with egress VLAN rewrite)");
621           break;
622         case SR_BEHAVIOR_DT6:
623           vlib_cli_output (vm,
624                            "\tAddress: \t%U/%u\n\tBehavior: \tDT6 (Endpoint with decapsulation and specific IPv6 table lookup)"
625                            "\n\tTable: %u", format_ip6_address, &ls->localsid,
626                            ls->localsid_prefix_len,
627                            fib_table_get_table_id (ls->vrf_index,
628                                                    FIB_PROTOCOL_IP6));
629           break;
630         case SR_BEHAVIOR_DT4:
631           vlib_cli_output (vm,
632                            "\tAddress: \t%U/%u\n\tBehavior: \tDT4 (Endpoint with decapsulation and specific IPv4 table lookup)"
633                            "\n\tTable: \t%u", format_ip6_address,
634                            &ls->localsid, ls->localsid_prefix_len,
635                            fib_table_get_table_id (ls->vrf_index,
636                                                    FIB_PROTOCOL_IP4));
637           break;
638         default:
639           if (ls->behavior >= SR_BEHAVIOR_LAST)
640             {
641               sr_localsid_fn_registration_t *plugin =
642                 pool_elt_at_index (sm->plugin_functions,
643                                    ls->behavior - SR_BEHAVIOR_LAST);
644
645               vlib_cli_output (vm, "\tAddress: \t%U/%u\n"
646                                "\tBehavior: \t%s (%s)\n\t%U",
647                                format_ip6_address, &ls->localsid,
648                                ls->localsid_prefix_len, plugin->keyword_str,
649                                plugin->def_str, plugin->ls_format,
650                                ls->plugin_mem);
651             }
652           else
653             //Should never get here...
654             vlib_cli_output (vm, "Internal error");
655           break;
656         }
657       if (ls->end_psp)
658         vlib_cli_output (vm, "\tPSP: \tTrue\n");
659
660       /* Print counters */
661       vlib_counter_t valid, invalid;
662       vlib_get_combined_counter (&(sm->sr_ls_valid_counters), i, &valid);
663       vlib_get_combined_counter (&(sm->sr_ls_invalid_counters), i, &invalid);
664       vlib_cli_output (vm, "\tGood traffic: \t[%Ld packets : %Ld bytes]\n",
665                        valid.packets, valid.bytes);
666       vlib_cli_output (vm, "\tBad traffic:  \t[%Ld packets : %Ld bytes]\n",
667                        invalid.packets, invalid.bytes);
668       vlib_cli_output (vm, "--------------------");
669     }
670   return 0;
671 }
672
673 VLIB_CLI_COMMAND (show_sr_localsid_command, static) = {
674   .path = "show sr localsids",
675   .short_help = "show sr localsids",
676   .function = show_sr_localsid_command_fn,
677 };
678
679 /**
680  * @brief Function to 'clear' ALL SR localsid counters
681  */
682 static clib_error_t *
683 clear_sr_localsid_counters_command_fn (vlib_main_t * vm,
684                                        unformat_input_t * input,
685                                        vlib_cli_command_t * cmd)
686 {
687   ip6_sr_main_t *sm = &sr_main;
688
689   vlib_clear_combined_counters (&(sm->sr_ls_valid_counters));
690   vlib_clear_combined_counters (&(sm->sr_ls_invalid_counters));
691
692   return 0;
693 }
694
695 VLIB_CLI_COMMAND (clear_sr_localsid_counters_command, static) = {
696   .path = "clear sr localsid-counters",
697   .short_help = "clear sr localsid-counters",
698   .function = clear_sr_localsid_counters_command_fn,
699 };
700
701 /************************ SR LocalSID graphs node ****************************/
702 /**
703  * @brief SR localsid node trace
704  */
705 typedef struct
706 {
707   ip6_address_t localsid;
708   u16 behavior;
709   u8 sr[256];
710   u8 num_segments;
711   u8 segments_left;
712 } sr_localsid_trace_t;
713
714 #define foreach_sr_localsid_error                                   \
715 _(NO_INNER_HEADER, "(SR-Error) No inner IP header")                 \
716 _(NO_MORE_SEGMENTS, "(SR-Error) No more segments")                  \
717 _(NO_SRH, "(SR-Error) No SR header")                                \
718 _(NO_PSP, "(SR-Error) PSP Not available (segments left > 0)")       \
719 _(NOT_LS, "(SR-Error) Decaps not available (segments left > 0)")    \
720 _(L2, "(SR-Error) SRv6 decapsulated a L2 frame without dest")
721
722 typedef enum
723 {
724 #define _(sym,str) SR_LOCALSID_ERROR_##sym,
725   foreach_sr_localsid_error
726 #undef _
727     SR_LOCALSID_N_ERROR,
728 } sr_localsid_error_t;
729
730 static char *sr_localsid_error_strings[] = {
731 #define _(sym,string) string,
732   foreach_sr_localsid_error
733 #undef _
734 };
735
736 #define foreach_sr_localsid_next        \
737 _(ERROR, "error-drop")                  \
738 _(IP6_LOOKUP, "ip6-lookup")             \
739 _(IP4_LOOKUP, "ip4-lookup")             \
740 _(IP6_REWRITE, "ip6-rewrite")           \
741 _(IP4_REWRITE, "ip4-rewrite")           \
742 _(INTERFACE_OUTPUT, "interface-output")
743
744 typedef enum
745 {
746 #define _(s,n) SR_LOCALSID_NEXT_##s,
747   foreach_sr_localsid_next
748 #undef _
749     SR_LOCALSID_N_NEXT,
750 } sr_localsid_next_t;
751
752 /**
753  * @brief SR LocalSID graph node trace function
754  *
755  * @see sr_localsid
756  */
757 u8 *
758 format_sr_localsid_trace (u8 * s, va_list * args)
759 {
760   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
761   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
762   sr_localsid_trace_t *t = va_arg (*args, sr_localsid_trace_t *);
763
764   s =
765     format (s, "SR-LOCALSID:\n\tLocalsid: %U\n", format_ip6_address,
766             &t->localsid);
767   switch (t->behavior)
768     {
769     case SR_BEHAVIOR_END:
770       s = format (s, "\tBehavior: End\n");
771       break;
772     case SR_BEHAVIOR_END_UN:
773       s = format (s, "\tBehavior: End.uN (flex)\n");
774       break;
775     case SR_BEHAVIOR_END_UN_PERF:
776       s = format (s, "\tBehavior: End.uN\n");
777       break;
778     case SR_BEHAVIOR_DX6:
779       s = format (s, "\tBehavior: Decapsulation with IPv6 L3 xconnect\n");
780       break;
781     case SR_BEHAVIOR_DX4:
782       s = format (s, "\tBehavior: Decapsulation with IPv4 L3 xconnect\n");
783       break;
784     case SR_BEHAVIOR_X:
785       s = format (s, "\tBehavior: IPv6 L3 xconnect\n");
786       break;
787     case SR_BEHAVIOR_T:
788       s = format (s, "\tBehavior: IPv6 specific table lookup\n");
789       break;
790     case SR_BEHAVIOR_DT6:
791       s = format (s, "\tBehavior: Decapsulation with IPv6 Table lookup\n");
792       break;
793     case SR_BEHAVIOR_DT4:
794       s = format (s, "\tBehavior: Decapsulation with IPv4 Table lookup\n");
795       break;
796     case SR_BEHAVIOR_DX2:
797       s = format (s, "\tBehavior: Decapsulation with L2 xconnect\n");
798       break;
799     default:
800       s = format (s, "\tBehavior: defined in plugin\n");        //TODO
801       break;
802     }
803   if (t->num_segments != 0xFF)
804     {
805       if (t->num_segments > 0)
806         {
807           s = format (s, "\tSegments left: %d\n", t->segments_left);
808           s = format (s, "\tSID list: [in ietf order]");
809           int i = 0;
810           for (i = 0; i < t->num_segments; i++)
811             {
812               s = format (s, "\n\t-> %U", format_ip6_address,
813                           (ip6_address_t *) & t->sr[i *
814                                                     sizeof (ip6_address_t)]);
815             }
816         }
817     }
818   return s;
819 }
820
821 /**
822  * @brief Function doing End processing.
823  */
824 static_always_inline void
825 end_srh_processing (vlib_node_runtime_t * node,
826                     vlib_buffer_t * b0,
827                     ip6_header_t * ip0,
828                     ip6_sr_header_t * sr0,
829                     ip6_sr_localsid_t * ls0,
830                     u32 * next0, u8 psp, ip6_ext_header_t * prev0)
831 {
832   ip6_address_t *new_dst0;
833
834   if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
835     {
836       if (sr0->segments_left == 1 && psp)
837         {
838           u32 new_l0, sr_len;
839           u64 *copy_dst0, *copy_src0;
840           u32 copy_len_u64s0 = 0;
841
842           ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
843           ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
844
845           /* Remove the SRH taking care of the rest of IPv6 ext header */
846           if (prev0)
847             prev0->next_hdr = sr0->protocol;
848           else
849             ip0->protocol = sr0->protocol;
850
851           sr_len = ip6_ext_header_len (sr0);
852           vlib_buffer_advance (b0, sr_len);
853           new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
854           ip0->payload_length = clib_host_to_net_u16 (new_l0);
855           copy_src0 = (u64 *) ip0;
856           copy_dst0 = copy_src0 + (sr0->length + 1);
857           /* number of 8 octet units to copy
858            * By default in absence of extension headers it is equal to length of ip6 header
859            * With extension headers it number of 8 octet units of ext headers preceding
860            * SR header
861            */
862           copy_len_u64s0 =
863             (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
864           copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
865           copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
866           copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
867           copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
868           copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
869
870           int i;
871           for (i = copy_len_u64s0 - 1; i >= 0; i--)
872             {
873               copy_dst0[i] = copy_src0[i];
874             }
875
876           if (ls0->behavior == SR_BEHAVIOR_X)
877             {
878               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
879               *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
880             }
881           else if (ls0->behavior == SR_BEHAVIOR_T)
882             {
883               vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
884             }
885         }
886       else if (PREDICT_TRUE (sr0->segments_left > 0))
887         {
888           sr0->segments_left -= 1;
889           new_dst0 = (ip6_address_t *) (sr0->segments);
890           new_dst0 += sr0->segments_left;
891           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
892           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
893
894           if (ls0->behavior == SR_BEHAVIOR_X)
895             {
896               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
897               *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
898             }
899           else if (ls0->behavior == SR_BEHAVIOR_T)
900             {
901               vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
902             }
903         }
904       else
905         {
906           *next0 = SR_LOCALSID_NEXT_ERROR;
907           b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
908         }
909     }
910   else
911     {
912       /* Error. Routing header of type != SR */
913       *next0 = SR_LOCALSID_NEXT_ERROR;
914       b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
915     }
916 }
917
918 /**
919  * @brief Function doing End uN processing.
920  */
921 static_always_inline void
922 end_un_srh_processing (vlib_node_runtime_t * node,
923                        vlib_buffer_t * b0,
924                        ip6_header_t * ip0,
925                        ip6_sr_header_t * sr0,
926                        ip6_sr_localsid_t * ls0,
927                        u32 * next0, u8 psp, ip6_ext_header_t * prev0)
928 {
929   ip6_address_t *new_dst0;
930   bool next_usid = false;
931   u8 next_usid_index;
932   u8 usid_len;
933   u8 index;
934
935   usid_len = ls0->usid_len;
936   next_usid_index = ls0->usid_next_index;
937
938   /* uSID */
939   for (index = 0; index < usid_len; index++)
940     {
941       if (ip0->dst_address.as_u8[next_usid_index + index] != 0)
942         {
943           next_usid = true;
944           break;
945         }
946     }
947
948   if (PREDICT_TRUE (next_usid))
949     {
950       u8 offset;
951
952       index = ls0->usid_index;
953
954       /* advance next usid */
955       for (offset = 0; offset < ls0->usid_next_len; offset++)
956         {
957           ip0->dst_address.as_u8[index + offset] =
958             ip0->dst_address.as_u8[next_usid_index + offset];
959         }
960
961       for (index = 16 - usid_len; index < 16; index++)
962         {
963           ip0->dst_address.as_u8[index] = 0;
964         }
965
966       return;
967     }
968
969   if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
970     {
971       if (sr0->segments_left == 1 && psp)
972         {
973           u32 new_l0, sr_len;
974           u64 *copy_dst0, *copy_src0;
975           u32 copy_len_u64s0 = 0;
976
977           ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
978           ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
979
980           /* Remove the SRH taking care of the rest of IPv6 ext header */
981           if (prev0)
982             prev0->next_hdr = sr0->protocol;
983           else
984             ip0->protocol = sr0->protocol;
985
986           sr_len = ip6_ext_header_len (sr0);
987           vlib_buffer_advance (b0, sr_len);
988           new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
989           ip0->payload_length = clib_host_to_net_u16 (new_l0);
990           copy_src0 = (u64 *) ip0;
991           copy_dst0 = copy_src0 + (sr0->length + 1);
992           /* number of 8 octet units to copy
993            * By default in absence of extension headers it is equal to length of ip6 header
994            * With extension headers it number of 8 octet units of ext headers preceding
995            * SR header
996            */
997           copy_len_u64s0 =
998             (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
999           copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
1000           copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
1001           copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
1002           copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
1003           copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
1004
1005           int i;
1006           for (i = copy_len_u64s0 - 1; i >= 0; i--)
1007             {
1008               copy_dst0[i] = copy_src0[i];
1009             }
1010         }
1011       else if (PREDICT_TRUE (sr0->segments_left > 0))
1012         {
1013           sr0->segments_left -= 1;
1014           new_dst0 = (ip6_address_t *) (sr0->segments);
1015           new_dst0 += sr0->segments_left;
1016           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1017           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1018         }
1019       else
1020         {
1021           *next0 = SR_LOCALSID_NEXT_ERROR;
1022           b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
1023         }
1024     }
1025   else
1026     {
1027       /* Error. Routing header of type != SR */
1028       *next0 = SR_LOCALSID_NEXT_ERROR;
1029       b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
1030     }
1031 }
1032
1033 static_always_inline void
1034 end_un_processing (ip6_header_t * ip0, ip6_sr_localsid_t * ls0)
1035 {
1036   u8 next_usid_index;
1037   u8 index;
1038   u8 offset;
1039
1040   /* uSID */
1041   index = ls0->usid_index;
1042   next_usid_index = ls0->usid_next_index;
1043
1044   /* advance next usid */
1045   for (offset = 0; offset < ls0->usid_next_len; offset++)
1046     {
1047       ip0->dst_address.as_u8[index + offset] =
1048         ip0->dst_address.as_u8[next_usid_index + offset];
1049     }
1050
1051   for (index = 16 - ls0->usid_len; index < 16; index++)
1052     {
1053       ip0->dst_address.as_u8[index] = 0;
1054     }
1055
1056   return;
1057 }
1058
1059 /*
1060  * @brief Function doing SRH processing for D* variants
1061  */
1062 static_always_inline void
1063 end_decaps_srh_processing (vlib_node_runtime_t * node,
1064                            vlib_buffer_t * b0,
1065                            ip6_header_t * ip0,
1066                            ip6_sr_header_t * sr0,
1067                            ip6_sr_localsid_t * ls0, u32 * next0)
1068 {
1069   /* Compute the size of the IPv6 header with all Ext. headers */
1070   u8 next_proto;
1071   ip6_ext_header_t *next_ext_header;
1072   u16 total_size = 0;
1073
1074   next_proto = ip0->protocol;
1075   next_ext_header = (void *) (ip0 + 1);
1076   total_size = sizeof (ip6_header_t);
1077   while (ip6_ext_hdr (next_proto))
1078     {
1079       total_size += ip6_ext_header_len (next_ext_header);
1080       next_proto = next_ext_header->next_hdr;
1081       next_ext_header = ip6_ext_next_header (next_ext_header);
1082     }
1083
1084   /* Ensure this is the last segment. Otherwise drop. */
1085   if (sr0 && sr0->segments_left != 0)
1086     {
1087       *next0 = SR_LOCALSID_NEXT_ERROR;
1088       b0->error = node->errors[SR_LOCALSID_ERROR_NOT_LS];
1089       return;
1090     }
1091
1092   switch (next_proto)
1093     {
1094     case IP_PROTOCOL_IPV6:
1095       /* Encap-End IPv6. Pop outer IPv6 header. */
1096       if (ls0->behavior == SR_BEHAVIOR_DX6)
1097         {
1098           vlib_buffer_advance (b0, total_size);
1099           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1100           *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
1101           return;
1102         }
1103       else if (ls0->behavior == SR_BEHAVIOR_DT6)
1104         {
1105           vlib_buffer_advance (b0, total_size);
1106           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1107           return;
1108         }
1109       break;
1110     case IP_PROTOCOL_IP_IN_IP:
1111       /* Encap-End IPv4. Pop outer IPv6 header */
1112       if (ls0->behavior == SR_BEHAVIOR_DX4)
1113         {
1114           vlib_buffer_advance (b0, total_size);
1115           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
1116           *next0 = SR_LOCALSID_NEXT_IP4_REWRITE;
1117           return;
1118         }
1119       else if (ls0->behavior == SR_BEHAVIOR_DT4)
1120         {
1121           vlib_buffer_advance (b0, total_size);
1122           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
1123           *next0 = SR_LOCALSID_NEXT_IP4_LOOKUP;
1124           return;
1125         }
1126       break;
1127     case IP_PROTOCOL_IP6_ETHERNET:
1128       /* L2 encaps */
1129       if (ls0->behavior == SR_BEHAVIOR_DX2)
1130         {
1131           vlib_buffer_advance (b0, total_size);
1132           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->sw_if_index;
1133           *next0 = SR_LOCALSID_NEXT_INTERFACE_OUTPUT;
1134           return;
1135         }
1136       break;
1137     }
1138   *next0 = SR_LOCALSID_NEXT_ERROR;
1139   b0->error = node->errors[SR_LOCALSID_ERROR_NO_INNER_HEADER];
1140   return;
1141 }
1142
1143 /**
1144  * @brief SR LocalSID graph node. Supports all default SR Endpoint variants with decaps
1145  */
1146 static uword
1147 sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1148                   vlib_frame_t * from_frame)
1149 {
1150   u32 n_left_from, next_index, *from, *to_next;
1151   ip6_sr_main_t *sm = &sr_main;
1152   from = vlib_frame_vector_args (from_frame);
1153   n_left_from = from_frame->n_vectors;
1154   next_index = node->cached_next_index;
1155   u32 thread_index = vm->thread_index;
1156
1157   while (n_left_from > 0)
1158     {
1159       u32 n_left_to_next;
1160       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1161
1162       /* Quad - Loop */
1163       while (n_left_from >= 8 && n_left_to_next >= 4)
1164         {
1165           u32 bi0, bi1, bi2, bi3;
1166           vlib_buffer_t *b0, *b1, *b2, *b3;
1167           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1168           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1169           u32 next0, next1, next2, next3;
1170           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1171           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1172
1173           /* Prefetch next iteration. */
1174           {
1175             vlib_buffer_t *p4, *p5, *p6, *p7;
1176
1177             p4 = vlib_get_buffer (vm, from[4]);
1178             p5 = vlib_get_buffer (vm, from[5]);
1179             p6 = vlib_get_buffer (vm, from[6]);
1180             p7 = vlib_get_buffer (vm, from[7]);
1181
1182             /* Prefetch the buffer header and packet for the N+4 loop iteration */
1183             vlib_prefetch_buffer_header (p4, LOAD);
1184             vlib_prefetch_buffer_header (p5, LOAD);
1185             vlib_prefetch_buffer_header (p6, LOAD);
1186             vlib_prefetch_buffer_header (p7, LOAD);
1187
1188             clib_prefetch_store (p4->data);
1189             clib_prefetch_store (p5->data);
1190             clib_prefetch_store (p6->data);
1191             clib_prefetch_store (p7->data);
1192           }
1193
1194           to_next[0] = bi0 = from[0];
1195           to_next[1] = bi1 = from[1];
1196           to_next[2] = bi2 = from[2];
1197           to_next[3] = bi3 = from[3];
1198           from += 4;
1199           to_next += 4;
1200           n_left_from -= 4;
1201           n_left_to_next -= 4;
1202
1203           b0 = vlib_get_buffer (vm, bi0);
1204           b1 = vlib_get_buffer (vm, bi1);
1205           b2 = vlib_get_buffer (vm, bi2);
1206           b3 = vlib_get_buffer (vm, bi3);
1207
1208           ls0 =
1209             pool_elt_at_index (sm->localsids,
1210                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1211           ls1 =
1212             pool_elt_at_index (sm->localsids,
1213                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1214           ls2 =
1215             pool_elt_at_index (sm->localsids,
1216                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1217           ls3 =
1218             pool_elt_at_index (sm->localsids,
1219                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1220
1221           ip0 = vlib_buffer_get_current (b0);
1222           ip1 = vlib_buffer_get_current (b1);
1223           ip2 = vlib_buffer_get_current (b2);
1224           ip3 = vlib_buffer_get_current (b3);
1225
1226           sr0 =
1227             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1228           sr1 =
1229             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, NULL);
1230           sr2 =
1231             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, NULL);
1232           sr3 =
1233             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, NULL);
1234
1235           end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1236           end_decaps_srh_processing (node, b1, ip1, sr1, ls1, &next1);
1237           end_decaps_srh_processing (node, b2, ip2, sr2, ls2, &next2);
1238           end_decaps_srh_processing (node, b3, ip3, sr3, ls3, &next3);
1239
1240           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1241             {
1242               sr_localsid_trace_t *tr =
1243                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1244               tr->num_segments = 0;
1245               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1246                            sizeof (tr->localsid.as_u8));
1247               tr->behavior = ls0->behavior;
1248               if (ip0 == vlib_buffer_get_current (b0))
1249                 {
1250                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1251                       && sr0->type == ROUTING_HEADER_TYPE_SR)
1252                     {
1253                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1254                       tr->num_segments =
1255                         sr0->length * 8 / sizeof (ip6_address_t);
1256                       tr->segments_left = sr0->segments_left;
1257                     }
1258                 }
1259               else
1260                 tr->num_segments = 0xFF;
1261             }
1262
1263           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1264             {
1265               sr_localsid_trace_t *tr =
1266                 vlib_add_trace (vm, node, b1, sizeof (*tr));
1267               tr->num_segments = 0;
1268               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1269                            sizeof (tr->localsid.as_u8));
1270               tr->behavior = ls1->behavior;
1271               if (ip1 == vlib_buffer_get_current (b1))
1272                 {
1273                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1274                       && sr1->type == ROUTING_HEADER_TYPE_SR)
1275                     {
1276                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1277                       tr->num_segments =
1278                         sr1->length * 8 / sizeof (ip6_address_t);
1279                       tr->segments_left = sr1->segments_left;
1280                     }
1281                 }
1282               else
1283                 tr->num_segments = 0xFF;
1284             }
1285
1286           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1287             {
1288               sr_localsid_trace_t *tr =
1289                 vlib_add_trace (vm, node, b2, sizeof (*tr));
1290               tr->num_segments = 0;
1291               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1292                            sizeof (tr->localsid.as_u8));
1293               tr->behavior = ls2->behavior;
1294               if (ip2 == vlib_buffer_get_current (b2))
1295                 {
1296                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1297                       && sr2->type == ROUTING_HEADER_TYPE_SR)
1298                     {
1299                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1300                       tr->num_segments =
1301                         sr2->length * 8 / sizeof (ip6_address_t);
1302                       tr->segments_left = sr2->segments_left;
1303                     }
1304                 }
1305               else
1306                 tr->num_segments = 0xFF;
1307             }
1308
1309           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1310             {
1311               sr_localsid_trace_t *tr =
1312                 vlib_add_trace (vm, node, b3, sizeof (*tr));
1313               tr->num_segments = 0;
1314               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1315                            sizeof (tr->localsid.as_u8));
1316               tr->behavior = ls3->behavior;
1317               if (ip3 == vlib_buffer_get_current (b3))
1318                 {
1319                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1320                       && sr3->type == ROUTING_HEADER_TYPE_SR)
1321                     {
1322                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1323                       tr->num_segments =
1324                         sr3->length * 8 / sizeof (ip6_address_t);
1325                       tr->segments_left = sr3->segments_left;
1326                     }
1327                 }
1328               else
1329                 tr->num_segments = 0xFF;
1330             }
1331
1332           vlib_increment_combined_counter
1333             (((next0 ==
1334                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1335               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1336              1, vlib_buffer_length_in_chain (vm, b0));
1337
1338           vlib_increment_combined_counter
1339             (((next1 ==
1340                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1341               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1342              1, vlib_buffer_length_in_chain (vm, b1));
1343
1344           vlib_increment_combined_counter
1345             (((next2 ==
1346                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1347               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1348              1, vlib_buffer_length_in_chain (vm, b2));
1349
1350           vlib_increment_combined_counter
1351             (((next3 ==
1352                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1353               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1354              1, vlib_buffer_length_in_chain (vm, b3));
1355
1356           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1357                                            n_left_to_next, bi0, bi1, bi2, bi3,
1358                                            next0, next1, next2, next3);
1359         }
1360
1361       /* Single loop for potentially the last three packets */
1362       while (n_left_from > 0 && n_left_to_next > 0)
1363         {
1364           u32 bi0;
1365           vlib_buffer_t *b0;
1366           ip6_header_t *ip0;
1367           ip6_sr_header_t *sr0;
1368           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1369           ip6_sr_localsid_t *ls0;
1370
1371           bi0 = from[0];
1372           to_next[0] = bi0;
1373           from += 1;
1374           to_next += 1;
1375           n_left_from -= 1;
1376           n_left_to_next -= 1;
1377
1378           b0 = vlib_get_buffer (vm, bi0);
1379           ip0 = vlib_buffer_get_current (b0);
1380
1381           /* Lookup the SR End behavior based on IP DA (adj) */
1382           ls0 =
1383             pool_elt_at_index (sm->localsids,
1384                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1385
1386           /* Find SRH as well as previous header */
1387           sr0 =
1388             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
1389
1390           /* SRH processing and End variants */
1391           end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
1392
1393           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1394             {
1395               sr_localsid_trace_t *tr =
1396                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1397               tr->num_segments = 0;
1398               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1399                            sizeof (tr->localsid.as_u8));
1400               tr->behavior = ls0->behavior;
1401               if (ip0 == vlib_buffer_get_current (b0))
1402                 {
1403                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1404                       && sr0->type == ROUTING_HEADER_TYPE_SR)
1405                     {
1406                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1407                       tr->num_segments =
1408                         sr0->length * 8 / sizeof (ip6_address_t);
1409                       tr->segments_left = sr0->segments_left;
1410                     }
1411                 }
1412               else
1413                 tr->num_segments = 0xFF;
1414             }
1415
1416           /* Increase the counters */
1417           vlib_increment_combined_counter
1418             (((next0 ==
1419                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1420               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1421              1, vlib_buffer_length_in_chain (vm, b0));
1422
1423           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1424                                            n_left_to_next, bi0, next0);
1425         }
1426       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1427     }
1428   return from_frame->n_vectors;
1429 }
1430
1431 VLIB_REGISTER_NODE (sr_localsid_d_node) = {
1432   .function = sr_localsid_d_fn,
1433   .name = "sr-localsid-d",
1434   .vector_size = sizeof (u32),
1435   .format_trace = format_sr_localsid_trace,
1436   .type = VLIB_NODE_TYPE_INTERNAL,
1437   .n_errors = SR_LOCALSID_N_ERROR,
1438   .error_strings = sr_localsid_error_strings,
1439   .n_next_nodes = SR_LOCALSID_N_NEXT,
1440   .next_nodes = {
1441 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1442     foreach_sr_localsid_next
1443 #undef _
1444   },
1445 };
1446
1447 /**
1448  * @brief SR LocalSID graph node. Supports all default SR Endpoint without decaps
1449  */
1450 static uword
1451 sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1452                 vlib_frame_t * from_frame)
1453 {
1454   u32 n_left_from, next_index, *from, *to_next;
1455   ip6_sr_main_t *sm = &sr_main;
1456   from = vlib_frame_vector_args (from_frame);
1457   n_left_from = from_frame->n_vectors;
1458   next_index = node->cached_next_index;
1459   u32 thread_index = vm->thread_index;
1460
1461   while (n_left_from > 0)
1462     {
1463       u32 n_left_to_next;
1464       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1465
1466       /* Quad - Loop */
1467       while (n_left_from >= 8 && n_left_to_next >= 4)
1468         {
1469           u32 bi0, bi1, bi2, bi3;
1470           vlib_buffer_t *b0, *b1, *b2, *b3;
1471           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1472           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1473           ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1474           u32 next0, next1, next2, next3;
1475           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1476           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1477
1478           /* Prefetch next iteration. */
1479           {
1480             vlib_buffer_t *p4, *p5, *p6, *p7;
1481
1482             p4 = vlib_get_buffer (vm, from[4]);
1483             p5 = vlib_get_buffer (vm, from[5]);
1484             p6 = vlib_get_buffer (vm, from[6]);
1485             p7 = vlib_get_buffer (vm, from[7]);
1486
1487             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1488             vlib_prefetch_buffer_header (p4, LOAD);
1489             vlib_prefetch_buffer_header (p5, LOAD);
1490             vlib_prefetch_buffer_header (p6, LOAD);
1491             vlib_prefetch_buffer_header (p7, LOAD);
1492
1493             clib_prefetch_store (p4->data);
1494             clib_prefetch_store (p5->data);
1495             clib_prefetch_store (p6->data);
1496             clib_prefetch_store (p7->data);
1497           }
1498
1499           to_next[0] = bi0 = from[0];
1500           to_next[1] = bi1 = from[1];
1501           to_next[2] = bi2 = from[2];
1502           to_next[3] = bi3 = from[3];
1503           from += 4;
1504           to_next += 4;
1505           n_left_from -= 4;
1506           n_left_to_next -= 4;
1507
1508           b0 = vlib_get_buffer (vm, bi0);
1509           b1 = vlib_get_buffer (vm, bi1);
1510           b2 = vlib_get_buffer (vm, bi2);
1511           b3 = vlib_get_buffer (vm, bi3);
1512
1513           ip0 = vlib_buffer_get_current (b0);
1514           ip1 = vlib_buffer_get_current (b1);
1515           ip2 = vlib_buffer_get_current (b2);
1516           ip3 = vlib_buffer_get_current (b3);
1517
1518           sr0 =
1519             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1520           sr1 =
1521             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1522           sr2 =
1523             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1524           sr3 =
1525             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1526
1527           ls0 =
1528             pool_elt_at_index (sm->localsids,
1529                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1530           ls1 =
1531             pool_elt_at_index (sm->localsids,
1532                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1533           ls2 =
1534             pool_elt_at_index (sm->localsids,
1535                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1536           ls3 =
1537             pool_elt_at_index (sm->localsids,
1538                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1539
1540           end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1541                               prev0);
1542           end_srh_processing (node, b1, ip1, sr1, ls1, &next1, ls1->end_psp,
1543                               prev1);
1544           end_srh_processing (node, b2, ip2, sr2, ls2, &next2, ls2->end_psp,
1545                               prev2);
1546           end_srh_processing (node, b3, ip3, sr3, ls3, &next3, ls3->end_psp,
1547                               prev3);
1548
1549           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1550             {
1551               sr_localsid_trace_t *tr =
1552                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1553               tr->num_segments = 0;
1554               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1555                            sizeof (tr->localsid.as_u8));
1556               tr->behavior = ls0->behavior;
1557               if (ip0 == vlib_buffer_get_current (b0))
1558                 {
1559                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1560                       && sr0->type == ROUTING_HEADER_TYPE_SR)
1561                     {
1562                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1563                       tr->num_segments =
1564                         sr0->length * 8 / sizeof (ip6_address_t);
1565                       tr->segments_left = sr0->segments_left;
1566                     }
1567                 }
1568               else
1569                 tr->num_segments = 0xFF;
1570             }
1571
1572           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1573             {
1574               sr_localsid_trace_t *tr =
1575                 vlib_add_trace (vm, node, b1, sizeof (*tr));
1576               tr->num_segments = 0;
1577               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1578                            sizeof (tr->localsid.as_u8));
1579               tr->behavior = ls1->behavior;
1580               if (ip1 == vlib_buffer_get_current (b1))
1581                 {
1582                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1583                       && sr1->type == ROUTING_HEADER_TYPE_SR)
1584                     {
1585                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1586                       tr->num_segments =
1587                         sr1->length * 8 / sizeof (ip6_address_t);
1588                       tr->segments_left = sr1->segments_left;
1589                     }
1590                 }
1591               else
1592                 tr->num_segments = 0xFF;
1593             }
1594
1595           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1596             {
1597               sr_localsid_trace_t *tr =
1598                 vlib_add_trace (vm, node, b2, sizeof (*tr));
1599               tr->num_segments = 0;
1600               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1601                            sizeof (tr->localsid.as_u8));
1602               tr->behavior = ls2->behavior;
1603               if (ip2 == vlib_buffer_get_current (b2))
1604                 {
1605                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1606                       && sr2->type == ROUTING_HEADER_TYPE_SR)
1607                     {
1608                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1609                       tr->num_segments =
1610                         sr2->length * 8 / sizeof (ip6_address_t);
1611                       tr->segments_left = sr2->segments_left;
1612                     }
1613                 }
1614               else
1615                 tr->num_segments = 0xFF;
1616             }
1617
1618           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1619             {
1620               sr_localsid_trace_t *tr =
1621                 vlib_add_trace (vm, node, b3, sizeof (*tr));
1622               tr->num_segments = 0;
1623               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1624                            sizeof (tr->localsid.as_u8));
1625               tr->behavior = ls3->behavior;
1626               if (ip3 == vlib_buffer_get_current (b3))
1627                 {
1628                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1629                       && sr3->type == ROUTING_HEADER_TYPE_SR)
1630                     {
1631                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1632                       tr->num_segments =
1633                         sr3->length * 8 / sizeof (ip6_address_t);
1634                       tr->segments_left = sr3->segments_left;
1635                     }
1636                 }
1637               else
1638                 tr->num_segments = 0xFF;
1639             }
1640
1641           vlib_increment_combined_counter
1642             (((next0 ==
1643                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1644               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1645              1, vlib_buffer_length_in_chain (vm, b0));
1646
1647           vlib_increment_combined_counter
1648             (((next1 ==
1649                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1650               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1651              1, vlib_buffer_length_in_chain (vm, b1));
1652
1653           vlib_increment_combined_counter
1654             (((next2 ==
1655                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1656               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1657              1, vlib_buffer_length_in_chain (vm, b2));
1658
1659           vlib_increment_combined_counter
1660             (((next3 ==
1661                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1662               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1663              1, vlib_buffer_length_in_chain (vm, b3));
1664
1665           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1666                                            n_left_to_next, bi0, bi1, bi2, bi3,
1667                                            next0, next1, next2, next3);
1668         }
1669
1670       /* Single loop for potentially the last three packets */
1671       while (n_left_from > 0 && n_left_to_next > 0)
1672         {
1673           u32 bi0;
1674           vlib_buffer_t *b0;
1675           ip6_header_t *ip0 = 0;
1676           ip6_ext_header_t *prev0;
1677           ip6_sr_header_t *sr0;
1678           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1679           ip6_sr_localsid_t *ls0;
1680
1681           bi0 = from[0];
1682           to_next[0] = bi0;
1683           from += 1;
1684           to_next += 1;
1685           n_left_from -= 1;
1686           n_left_to_next -= 1;
1687
1688           b0 = vlib_get_buffer (vm, bi0);
1689           ip0 = vlib_buffer_get_current (b0);
1690           sr0 =
1691             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1692
1693           /* Lookup the SR End behavior based on IP DA (adj) */
1694           ls0 =
1695             pool_elt_at_index (sm->localsids,
1696                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1697
1698           /* SRH processing */
1699           end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
1700                               prev0);
1701
1702           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1703             {
1704               sr_localsid_trace_t *tr =
1705                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1706               tr->num_segments = 0;
1707               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1708                            sizeof (tr->localsid.as_u8));
1709               tr->behavior = ls0->behavior;
1710               if (ip0 == vlib_buffer_get_current (b0))
1711                 {
1712                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1713                       && sr0->type == ROUTING_HEADER_TYPE_SR)
1714                     {
1715                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1716                       tr->num_segments =
1717                         sr0->length * 8 / sizeof (ip6_address_t);
1718                       tr->segments_left = sr0->segments_left;
1719                     }
1720                 }
1721               else
1722                 tr->num_segments = 0xFF;
1723             }
1724
1725           vlib_increment_combined_counter
1726             (((next0 ==
1727                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1728               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1729              1, vlib_buffer_length_in_chain (vm, b0));
1730
1731           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1732                                            n_left_to_next, bi0, next0);
1733         }
1734       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1735     }
1736   return from_frame->n_vectors;
1737 }
1738
1739 VLIB_REGISTER_NODE (sr_localsid_node) = {
1740   .function = sr_localsid_fn,
1741   .name = "sr-localsid",
1742   .vector_size = sizeof (u32),
1743   .format_trace = format_sr_localsid_trace,
1744   .type = VLIB_NODE_TYPE_INTERNAL,
1745   .n_errors = SR_LOCALSID_N_ERROR,
1746   .error_strings = sr_localsid_error_strings,
1747   .n_next_nodes = SR_LOCALSID_N_NEXT,
1748   .next_nodes = {
1749 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
1750     foreach_sr_localsid_next
1751 #undef _
1752   },
1753 };
1754
1755 /**
1756  * @brief SR LocalSID uN graph node. Supports all default SR Endpoint without decaps
1757  */
1758 static uword
1759 sr_localsid_un_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1760                    vlib_frame_t * from_frame)
1761 {
1762   u32 n_left_from, next_index, *from, *to_next;
1763   ip6_sr_main_t *sm = &sr_main;
1764   from = vlib_frame_vector_args (from_frame);
1765   n_left_from = from_frame->n_vectors;
1766   next_index = node->cached_next_index;
1767   u32 thread_index = vm->thread_index;
1768
1769   while (n_left_from > 0)
1770     {
1771       u32 n_left_to_next;
1772       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1773
1774       /* Quad - Loop */
1775       while (n_left_from >= 8 && n_left_to_next >= 4)
1776         {
1777           u32 bi0, bi1, bi2, bi3;
1778           vlib_buffer_t *b0, *b1, *b2, *b3;
1779           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1780           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1781           ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
1782           u32 next0, next1, next2, next3;
1783           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1784           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
1785
1786           /* Prefetch next iteration. */
1787           {
1788             vlib_buffer_t *p4, *p5, *p6, *p7;
1789
1790             p4 = vlib_get_buffer (vm, from[4]);
1791             p5 = vlib_get_buffer (vm, from[5]);
1792             p6 = vlib_get_buffer (vm, from[6]);
1793             p7 = vlib_get_buffer (vm, from[7]);
1794
1795             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1796             vlib_prefetch_buffer_header (p4, LOAD);
1797             vlib_prefetch_buffer_header (p5, LOAD);
1798             vlib_prefetch_buffer_header (p6, LOAD);
1799             vlib_prefetch_buffer_header (p7, LOAD);
1800
1801             clib_prefetch_store (p4->data);
1802             clib_prefetch_store (p5->data);
1803             clib_prefetch_store (p6->data);
1804             clib_prefetch_store (p7->data);
1805           }
1806
1807           to_next[0] = bi0 = from[0];
1808           to_next[1] = bi1 = from[1];
1809           to_next[2] = bi2 = from[2];
1810           to_next[3] = bi3 = from[3];
1811           from += 4;
1812           to_next += 4;
1813           n_left_from -= 4;
1814           n_left_to_next -= 4;
1815
1816           b0 = vlib_get_buffer (vm, bi0);
1817           b1 = vlib_get_buffer (vm, bi1);
1818           b2 = vlib_get_buffer (vm, bi2);
1819           b3 = vlib_get_buffer (vm, bi3);
1820
1821           ip0 = vlib_buffer_get_current (b0);
1822           ip1 = vlib_buffer_get_current (b1);
1823           ip2 = vlib_buffer_get_current (b2);
1824           ip3 = vlib_buffer_get_current (b3);
1825
1826           sr0 =
1827             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
1828           sr1 =
1829             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
1830           sr2 =
1831             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
1832           sr3 =
1833             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
1834
1835           ls0 =
1836             pool_elt_at_index (sm->localsids,
1837                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1838           ls1 =
1839             pool_elt_at_index (sm->localsids,
1840                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1841           ls2 =
1842             pool_elt_at_index (sm->localsids,
1843                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1844           ls3 =
1845             pool_elt_at_index (sm->localsids,
1846                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1847
1848           end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
1849                                  ls0->end_psp, prev0);
1850           end_un_srh_processing (node, b1, ip1, sr1, ls1, &next1,
1851                                  ls1->end_psp, prev1);
1852           end_un_srh_processing (node, b2, ip2, sr2, ls2, &next2,
1853                                  ls2->end_psp, prev2);
1854           end_un_srh_processing (node, b3, ip3, sr3, ls3, &next3,
1855                                  ls3->end_psp, prev3);
1856
1857           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1858             {
1859               sr_localsid_trace_t *tr =
1860                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1861               tr->num_segments = 0;
1862               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
1863                            sizeof (tr->localsid.as_u8));
1864               tr->behavior = ls0->behavior;
1865               if (ip0 == vlib_buffer_get_current (b0))
1866                 {
1867                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
1868                       && sr0->type == ROUTING_HEADER_TYPE_SR)
1869                     {
1870                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
1871                       tr->num_segments =
1872                         sr0->length * 8 / sizeof (ip6_address_t);
1873                       tr->segments_left = sr0->segments_left;
1874                     }
1875                 }
1876               else
1877                 tr->num_segments = 0xFF;
1878             }
1879
1880           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1881             {
1882               sr_localsid_trace_t *tr =
1883                 vlib_add_trace (vm, node, b1, sizeof (*tr));
1884               tr->num_segments = 0;
1885               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
1886                            sizeof (tr->localsid.as_u8));
1887               tr->behavior = ls1->behavior;
1888               if (ip1 == vlib_buffer_get_current (b1))
1889                 {
1890                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
1891                       && sr1->type == ROUTING_HEADER_TYPE_SR)
1892                     {
1893                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
1894                       tr->num_segments =
1895                         sr1->length * 8 / sizeof (ip6_address_t);
1896                       tr->segments_left = sr1->segments_left;
1897                     }
1898                 }
1899               else
1900                 tr->num_segments = 0xFF;
1901             }
1902
1903           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1904             {
1905               sr_localsid_trace_t *tr =
1906                 vlib_add_trace (vm, node, b2, sizeof (*tr));
1907               tr->num_segments = 0;
1908               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
1909                            sizeof (tr->localsid.as_u8));
1910               tr->behavior = ls2->behavior;
1911               if (ip2 == vlib_buffer_get_current (b2))
1912                 {
1913                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
1914                       && sr2->type == ROUTING_HEADER_TYPE_SR)
1915                     {
1916                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
1917                       tr->num_segments =
1918                         sr2->length * 8 / sizeof (ip6_address_t);
1919                       tr->segments_left = sr2->segments_left;
1920                     }
1921                 }
1922               else
1923                 tr->num_segments = 0xFF;
1924             }
1925
1926           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1927             {
1928               sr_localsid_trace_t *tr =
1929                 vlib_add_trace (vm, node, b3, sizeof (*tr));
1930               tr->num_segments = 0;
1931               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
1932                            sizeof (tr->localsid.as_u8));
1933               tr->behavior = ls3->behavior;
1934               if (ip3 == vlib_buffer_get_current (b3))
1935                 {
1936                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
1937                       && sr3->type == ROUTING_HEADER_TYPE_SR)
1938                     {
1939                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
1940                       tr->num_segments =
1941                         sr3->length * 8 / sizeof (ip6_address_t);
1942                       tr->segments_left = sr3->segments_left;
1943                     }
1944                 }
1945               else
1946                 tr->num_segments = 0xFF;
1947             }
1948
1949           vlib_increment_combined_counter
1950             (((next0 ==
1951                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1952               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
1953              1, vlib_buffer_length_in_chain (vm, b0));
1954
1955           vlib_increment_combined_counter
1956             (((next1 ==
1957                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1958               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
1959              1, vlib_buffer_length_in_chain (vm, b1));
1960
1961           vlib_increment_combined_counter
1962             (((next2 ==
1963                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1964               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
1965              1, vlib_buffer_length_in_chain (vm, b2));
1966
1967           vlib_increment_combined_counter
1968             (((next3 ==
1969                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
1970               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
1971              1, vlib_buffer_length_in_chain (vm, b3));
1972
1973           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1974                                            n_left_to_next, bi0, bi1, bi2, bi3,
1975                                            next0, next1, next2, next3);
1976         }
1977
1978       /* Single loop for potentially the last three packets */
1979       while (n_left_from > 0 && n_left_to_next > 0)
1980         {
1981           u32 bi0;
1982           vlib_buffer_t *b0;
1983           ip6_header_t *ip0 = 0;
1984           ip6_ext_header_t *prev0;
1985           ip6_sr_header_t *sr0;
1986           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
1987           ip6_sr_localsid_t *ls0;
1988
1989           bi0 = from[0];
1990           to_next[0] = bi0;
1991           from += 1;
1992           to_next += 1;
1993           n_left_from -= 1;
1994           n_left_to_next -= 1;
1995
1996           b0 = vlib_get_buffer (vm, bi0);
1997           ip0 = vlib_buffer_get_current (b0);
1998           sr0 =
1999             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
2000
2001           /* Lookup the SR End behavior based on IP DA (adj) */
2002           ls0 =
2003             pool_elt_at_index (sm->localsids,
2004                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2005
2006           /* SRH processing */
2007           end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
2008                                  ls0->end_psp, prev0);
2009
2010           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2011             {
2012               sr_localsid_trace_t *tr =
2013                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2014               tr->num_segments = 0;
2015               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2016                            sizeof (tr->localsid.as_u8));
2017               tr->behavior = ls0->behavior;
2018               if (ip0 == vlib_buffer_get_current (b0))
2019                 {
2020                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
2021                       && sr0->type == ROUTING_HEADER_TYPE_SR)
2022                     {
2023                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
2024                       tr->num_segments =
2025                         sr0->length * 8 / sizeof (ip6_address_t);
2026                       tr->segments_left = sr0->segments_left;
2027                     }
2028                 }
2029               else
2030                 tr->num_segments = 0xFF;
2031             }
2032
2033           vlib_increment_combined_counter
2034             (((next0 ==
2035                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
2036               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
2037              1, vlib_buffer_length_in_chain (vm, b0));
2038
2039           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2040                                            n_left_to_next, bi0, next0);
2041         }
2042       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2043     }
2044   return from_frame->n_vectors;
2045 }
2046
2047 VLIB_REGISTER_NODE (sr_localsid_un_node) = {
2048   .function = sr_localsid_un_fn,
2049   .name = "sr-localsid-un",
2050   .vector_size = sizeof (u32),
2051   .format_trace = format_sr_localsid_trace,
2052   .type = VLIB_NODE_TYPE_INTERNAL,
2053   .n_errors = SR_LOCALSID_N_ERROR,
2054   .error_strings = sr_localsid_error_strings,
2055   .n_next_nodes = SR_LOCALSID_N_NEXT,
2056   .next_nodes = {
2057 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2058     foreach_sr_localsid_next
2059 #undef _
2060   },
2061 };
2062
2063 static uword
2064 sr_localsid_un_perf_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
2065                         vlib_frame_t * from_frame)
2066 {
2067   u32 n_left_from, next_index, *from, *to_next;
2068   ip6_sr_main_t *sm = &sr_main;
2069   from = vlib_frame_vector_args (from_frame);
2070   n_left_from = from_frame->n_vectors;
2071   next_index = node->cached_next_index;
2072   u32 thread_index = vm->thread_index;
2073
2074   while (n_left_from > 0)
2075     {
2076       u32 n_left_to_next;
2077       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2078
2079       /* Quad - Loop */
2080       while (n_left_from >= 8 && n_left_to_next >= 4)
2081         {
2082           u32 bi0, bi1, bi2, bi3;
2083           vlib_buffer_t *b0, *b1, *b2, *b3;
2084           ip6_header_t *ip0, *ip1, *ip2, *ip3;
2085           u32 next0, next1, next2, next3;
2086           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2087           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
2088
2089           /* Prefetch next iteration. */
2090           {
2091             vlib_buffer_t *p4, *p5, *p6, *p7;
2092
2093             p4 = vlib_get_buffer (vm, from[4]);
2094             p5 = vlib_get_buffer (vm, from[5]);
2095             p6 = vlib_get_buffer (vm, from[6]);
2096             p7 = vlib_get_buffer (vm, from[7]);
2097
2098             /* Prefetch the buffer header and packet for the N+2 loop iteration */
2099             vlib_prefetch_buffer_header (p4, LOAD);
2100             vlib_prefetch_buffer_header (p5, LOAD);
2101             vlib_prefetch_buffer_header (p6, LOAD);
2102             vlib_prefetch_buffer_header (p7, LOAD);
2103
2104             clib_prefetch_store (p4->data);
2105             clib_prefetch_store (p5->data);
2106             clib_prefetch_store (p6->data);
2107             clib_prefetch_store (p7->data);
2108           }
2109
2110           to_next[0] = bi0 = from[0];
2111           to_next[1] = bi1 = from[1];
2112           to_next[2] = bi2 = from[2];
2113           to_next[3] = bi3 = from[3];
2114           from += 4;
2115           to_next += 4;
2116           n_left_from -= 4;
2117           n_left_to_next -= 4;
2118
2119           b0 = vlib_get_buffer (vm, bi0);
2120           b1 = vlib_get_buffer (vm, bi1);
2121           b2 = vlib_get_buffer (vm, bi2);
2122           b3 = vlib_get_buffer (vm, bi3);
2123
2124           ip0 = vlib_buffer_get_current (b0);
2125           ip1 = vlib_buffer_get_current (b1);
2126           ip2 = vlib_buffer_get_current (b2);
2127           ip3 = vlib_buffer_get_current (b3);
2128
2129           ls0 =
2130             pool_elt_at_index (sm->localsids,
2131                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2132           ls1 =
2133             pool_elt_at_index (sm->localsids,
2134                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2135           ls2 =
2136             pool_elt_at_index (sm->localsids,
2137                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2138           ls3 =
2139             pool_elt_at_index (sm->localsids,
2140                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2141
2142           end_un_processing (ip0, ls0);
2143           end_un_processing (ip1, ls1);
2144           end_un_processing (ip2, ls2);
2145           end_un_processing (ip3, ls3);
2146
2147           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2148             {
2149               sr_localsid_trace_t *tr =
2150                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2151               tr->num_segments = 0;
2152               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2153                            sizeof (tr->localsid.as_u8));
2154               tr->behavior = ls0->behavior;
2155             }
2156
2157           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2158             {
2159               sr_localsid_trace_t *tr =
2160                 vlib_add_trace (vm, node, b1, sizeof (*tr));
2161               tr->num_segments = 0;
2162               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
2163                            sizeof (tr->localsid.as_u8));
2164               tr->behavior = ls1->behavior;
2165             }
2166
2167           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2168             {
2169               sr_localsid_trace_t *tr =
2170                 vlib_add_trace (vm, node, b2, sizeof (*tr));
2171               tr->num_segments = 0;
2172               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
2173                            sizeof (tr->localsid.as_u8));
2174               tr->behavior = ls2->behavior;
2175             }
2176
2177           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2178             {
2179               sr_localsid_trace_t *tr =
2180                 vlib_add_trace (vm, node, b3, sizeof (*tr));
2181               tr->num_segments = 0;
2182               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
2183                            sizeof (tr->localsid.as_u8));
2184               tr->behavior = ls3->behavior;
2185             }
2186
2187           vlib_increment_combined_counter
2188             (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2189              1, vlib_buffer_length_in_chain (vm, b0));
2190
2191           vlib_increment_combined_counter
2192             (&(sm->sr_ls_valid_counters), thread_index, ls1 - sm->localsids,
2193              1, vlib_buffer_length_in_chain (vm, b1));
2194
2195           vlib_increment_combined_counter
2196             (&(sm->sr_ls_valid_counters), thread_index, ls2 - sm->localsids,
2197              1, vlib_buffer_length_in_chain (vm, b2));
2198
2199           vlib_increment_combined_counter
2200             (&(sm->sr_ls_valid_counters), thread_index, ls3 - sm->localsids,
2201              1, vlib_buffer_length_in_chain (vm, b3));
2202
2203           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2204                                            n_left_to_next, bi0, bi1, bi2, bi3,
2205                                            next0, next1, next2, next3);
2206         }
2207
2208       /* Single loop for potentially the last three packets */
2209       while (n_left_from > 0 && n_left_to_next > 0)
2210         {
2211           u32 bi0;
2212           vlib_buffer_t *b0;
2213           ip6_header_t *ip0 = 0;
2214           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
2215           ip6_sr_localsid_t *ls0;
2216
2217           bi0 = from[0];
2218           to_next[0] = bi0;
2219           from += 1;
2220           to_next += 1;
2221           n_left_from -= 1;
2222           n_left_to_next -= 1;
2223
2224           b0 = vlib_get_buffer (vm, bi0);
2225           ip0 = vlib_buffer_get_current (b0);
2226
2227           /* Lookup the SR End behavior based on IP DA (adj) */
2228           ls0 =
2229             pool_elt_at_index (sm->localsids,
2230                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2231
2232           /* SRH processing */
2233           end_un_processing (ip0, ls0);
2234
2235           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2236             {
2237               sr_localsid_trace_t *tr =
2238                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2239               tr->num_segments = 0;
2240               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
2241                            sizeof (tr->localsid.as_u8));
2242               tr->behavior = ls0->behavior;
2243             }
2244
2245           vlib_increment_combined_counter
2246             (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
2247              1, vlib_buffer_length_in_chain (vm, b0));
2248
2249           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2250                                            n_left_to_next, bi0, next0);
2251         }
2252       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2253     }
2254   return from_frame->n_vectors;
2255 }
2256
2257 VLIB_REGISTER_NODE (sr_localsid_un_perf_node) = {
2258   .function = sr_localsid_un_perf_fn,
2259   .name = "sr-localsid-un-perf",
2260   .vector_size = sizeof (u32),
2261   .format_trace = format_sr_localsid_trace,
2262   .type = VLIB_NODE_TYPE_INTERNAL,
2263   .n_errors = SR_LOCALSID_N_ERROR,
2264   .error_strings = sr_localsid_error_strings,
2265   .n_next_nodes = SR_LOCALSID_N_NEXT,
2266   .next_nodes = {
2267 #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
2268     foreach_sr_localsid_next
2269 #undef _
2270   },
2271 };
2272
2273 static u8 *
2274 format_sr_dpo (u8 * s, va_list * args)
2275 {
2276   index_t index = va_arg (*args, index_t);
2277   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
2278
2279   return (format (s, "SR: localsid_index:[%d]", index));
2280 }
2281
2282 const static dpo_vft_t sr_loc_vft = {
2283   .dv_lock = sr_dpo_lock,
2284   .dv_unlock = sr_dpo_unlock,
2285   .dv_format = format_sr_dpo,
2286 };
2287
2288 const static char *const sr_loc_ip6_nodes[] = {
2289   "sr-localsid",
2290   NULL,
2291 };
2292
2293 const static char *const *const sr_loc_nodes[DPO_PROTO_NUM] = {
2294   [DPO_PROTO_IP6] = sr_loc_ip6_nodes,
2295 };
2296
2297 const static char *const sr_loc_d_ip6_nodes[] = {
2298   "sr-localsid-d",
2299   NULL,
2300 };
2301
2302 const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
2303   [DPO_PROTO_IP6] = sr_loc_d_ip6_nodes,
2304 };
2305
2306 const static char *const sr_loc_un_ip6_nodes[] = {
2307   "sr-localsid-un",
2308   NULL,
2309 };
2310
2311 const static char *const *const sr_loc_un_nodes[DPO_PROTO_NUM] = {
2312   [DPO_PROTO_IP6] = sr_loc_un_ip6_nodes,
2313 };
2314
2315 const static char *const sr_loc_un_perf_ip6_nodes[] = {
2316   "sr-localsid-un-perf",
2317   NULL,
2318 };
2319
2320 const static char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM] = {
2321   [DPO_PROTO_IP6] = sr_loc_un_perf_ip6_nodes,
2322 };
2323
2324 /*************************** SR LocalSID plugins ******************************/
2325 /**
2326  * @brief SR LocalSID plugin registry
2327  */
2328 int
2329 sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
2330                                u8 * keyword_str, u8 * def_str,
2331                                u8 * params_str, u8 prefix_length,
2332                                dpo_type_t * dpo,
2333                                format_function_t * ls_format,
2334                                unformat_function_t * ls_unformat,
2335                                sr_plugin_callback_t * creation_fn,
2336                                sr_plugin_callback_t * removal_fn)
2337 {
2338   ip6_sr_main_t *sm = &sr_main;
2339   uword *p;
2340
2341   sr_localsid_fn_registration_t *plugin;
2342
2343   /* Did this function exist? If so update it */
2344   p = hash_get_mem (sm->plugin_functions_by_key, fn_name);
2345   if (p)
2346     {
2347       plugin = pool_elt_at_index (sm->plugin_functions, p[0]);
2348     }
2349   /* Else create a new one and set hash key */
2350   else
2351     {
2352       pool_get (sm->plugin_functions, plugin);
2353       hash_set_mem (sm->plugin_functions_by_key, fn_name,
2354                     plugin - sm->plugin_functions);
2355     }
2356
2357   clib_memset (plugin, 0, sizeof (*plugin));
2358
2359   plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
2360   plugin->sr_localsid_function_number += SR_BEHAVIOR_LAST;
2361   plugin->prefix_length = prefix_length;
2362   plugin->ls_format = ls_format;
2363   plugin->ls_unformat = ls_unformat;
2364   plugin->creation = creation_fn;
2365   plugin->removal = removal_fn;
2366   clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
2367   plugin->function_name = format (0, "%s%c", fn_name, 0);
2368   plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
2369   plugin->def_str = format (0, "%s%c", def_str, 0);
2370   plugin->params_str = format (0, "%s%c", params_str, 0);
2371
2372   return plugin->sr_localsid_function_number;
2373 }
2374
2375 /**
2376  * @brief CLI function to 'show' all available SR LocalSID behaviors
2377  */
2378 static clib_error_t *
2379 show_sr_localsid_behaviors_command_fn (vlib_main_t * vm,
2380                                        unformat_input_t * input,
2381                                        vlib_cli_command_t * cmd)
2382 {
2383   ip6_sr_main_t *sm = &sr_main;
2384   sr_localsid_fn_registration_t *plugin;
2385   sr_localsid_fn_registration_t **plugins_vec = 0;
2386   int i;
2387
2388   vlib_cli_output (vm,
2389                    "SR LocalSIDs behaviors:\n-----------------------\n\n");
2390
2391   pool_foreach (plugin, sm->plugin_functions)
2392     { vec_add1 (plugins_vec, plugin); }
2393
2394   /* Print static behaviors */
2395   vlib_cli_output (vm, "Default behaviors:\n"
2396                    "\tEnd\t-> Endpoint.\n"
2397                    "\tEnd.X\t-> Endpoint with Layer-3 cross-connect.\n"
2398                    "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2399                    "\tEnd.T\t-> Endpoint with specific IPv6 table lookup.\n"
2400                    "\t\tParameters: '<fib_table>'\n"
2401                    "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
2402                    "\t\tParameters: '<iface>'\n"
2403                    "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
2404                    "\t\tParameters: '<iface> <ip6_next_hop>'\n"
2405                    "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
2406                    "\t\tParameters: '<iface> <ip4_next_hop>'\n"
2407                    "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
2408                    "\t\tParameters: '<ip6_fib_table>'\n"
2409                    "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
2410                    "\t\tParameters: '<ip4_fib_table>'\n");
2411   vlib_cli_output (vm, "Plugin behaviors:\n");
2412   for (i = 0; i < vec_len (plugins_vec); i++)
2413     {
2414       plugin = plugins_vec[i];
2415       vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
2416                        plugin->def_str);
2417       vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
2418     }
2419   return 0;
2420 }
2421
2422 VLIB_CLI_COMMAND (show_sr_localsid_behaviors_command, static) = {
2423   .path = "show sr localsids behaviors",
2424   .short_help = "show sr localsids behaviors",
2425   .function = show_sr_localsid_behaviors_command_fn,
2426 };
2427
2428 /**
2429  * @brief SR LocalSID initialization
2430  */
2431 clib_error_t *
2432 sr_localsids_init (vlib_main_t * vm)
2433 {
2434   /* Init memory for function keys */
2435   ip6_sr_main_t *sm = &sr_main;
2436   mhash_init (&sm->sr_localsids_index_hash, sizeof (uword),
2437               sizeof (sr_localsid_key_t));
2438   /* Init SR behaviors DPO type */
2439   sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes);
2440   /* Init SR behaviors DPO type */
2441   sr_localsid_d_dpo_type =
2442     dpo_register_new_type (&sr_loc_vft, sr_loc_d_nodes);
2443   /* Init SR bhaviors DPO type */
2444   sr_localsid_un_dpo_type =
2445     dpo_register_new_type (&sr_loc_vft, sr_loc_un_nodes);
2446   sr_localsid_un_perf_dpo_type =
2447     dpo_register_new_type (&sr_loc_vft, sr_loc_un_perf_nodes);
2448   /* Init memory for localsid plugins */
2449   sm->plugin_functions_by_key = hash_create_string (0, sizeof (uword));
2450   return 0;
2451 }
2452
2453 VLIB_INIT_FUNCTION (sr_localsids_init);
2454 /*
2455 * fd.io coding-style-patch-verification: ON
2456 *
2457 * Local Variables:
2458 * eval: (c-set-style "gnu")
2459 * End:
2460 */