sr: Show IPv6 address used as SRv6 Encaps source
[vpp.git] / src / vnet / srv6 / sr_policy_rewrite.c
1 /*
2  * sr_policy_rewrite.c: ipv6 sr policy creation
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 SR policy creation and application
21  *
22  * Create an SR policy.
23  * An SR policy can be either of 'default' type or 'spray' type
24  * An SR policy has attached a list of SID lists.
25  * In case the SR policy is a default one it will load balance among them.
26  * An SR policy has associated a BindingSID.
27  * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28  * associated to such bindingSID will be applied to such packet.
29  *
30  * SR policies can be applied either by using IPv6 encapsulation or
31  * SRH insertion. Both methods can be found on this file.
32  *
33  * Traffic input usually is IPv6 packets. However it is possible to have
34  * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
35  *
36  * This file provides the appropiates VPP graph nodes to do any of these
37  * methods.
38  *
39  */
40
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip4_inlines.h>
45 #include <vnet/ip/ip6_inlines.h>
46 #include <vnet/srv6/sr_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
50
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
53
54 /**
55  * @brief SR policy rewrite trace
56  */
57 typedef struct
58 {
59   ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
61
62 /* Graph arcs */
63 #define foreach_sr_policy_rewrite_next     \
64 _(IP6_LOOKUP, "ip6-lookup")         \
65 _(ERROR, "error-drop")
66
67 typedef enum
68 {
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70   foreach_sr_policy_rewrite_next
71 #undef _
72     SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
74
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error                     \
77 _(INTERNAL_ERROR, "Segment Routing undefined error")        \
78 _(BSID_ZERO, "BSID with SL = 0")                            \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets")                 \
80 _(COUNTER_ENCAP, "SR: Encaps packets")                      \
81 _(COUNTER_INSERT, "SR: SRH inserted packets")               \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
83
84 typedef enum
85 {
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87   foreach_sr_policy_rewrite_error
88 #undef _
89     SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
91
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94   foreach_sr_policy_rewrite_error
95 #undef _
96 };
97
98 /**
99  * @brief Dynamically added SR SL DPO type
100  */
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
105
106 /**
107  * @brief IPv6 SA for encapsulated packets
108  */
109 static ip6_address_t sr_pr_encaps_src;
110 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
111
112 /******************* SR rewrite set encaps IPv6 source addr *******************/
113 /* Note:  This is temporal. We don't know whether to follow this path or
114           take the ip address of a loopback interface or even the OIF         */
115
116 void
117 sr_set_source (ip6_address_t * address)
118 {
119   clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
120 }
121
122 ip6_address_t *
123 sr_get_encaps_source ()
124 {
125   return &sr_pr_encaps_src;
126 }
127
128 static clib_error_t *
129 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130                        vlib_cli_command_t * cmd)
131 {
132   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
133     {
134       if (unformat
135           (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
136         return 0;
137       else
138         return clib_error_return (0, "No address specified");
139     }
140   return clib_error_return (0, "No address specified");
141 }
142
143 /* *INDENT-OFF* */
144 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145   .path = "set sr encaps source",
146   .short_help = "set sr encaps source addr <ip6_addr>",
147   .function = set_sr_src_command_fn,
148 };
149 /* *INDENT-ON* */
150
151 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
152
153 void
154 sr_set_hop_limit (u8 hop_limit)
155 {
156   sr_pr_encaps_hop_limit = hop_limit;
157 }
158
159 u8
160 sr_get_hop_limit (void)
161 {
162   return sr_pr_encaps_hop_limit;
163 }
164
165 static clib_error_t *
166 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167                              vlib_cli_command_t * cmd)
168 {
169   int hop_limit = sr_get_hop_limit ();
170
171   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172     return clib_error_return (0, "No value specified");
173   if (!unformat (input, "%d", &hop_limit))
174     return clib_error_return (0, "Invalid value");
175   if (hop_limit <= 0 || hop_limit > 255)
176     return clib_error_return (0, "Value out of range [1-255]");
177   sr_pr_encaps_hop_limit = (u8) hop_limit;
178   return 0;
179 }
180
181 /* *INDENT-OFF* */
182 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183   .path = "set sr encaps hop-limit",
184   .short_help = "set sr encaps hop-limit <value>",
185   .function = set_sr_hop_limit_command_fn,
186 };
187 /* *INDENT-ON* */
188
189 /*********************** SR rewrite string computation ************************/
190 /**
191  * @brief SR rewrite string computation for IPv6 encapsulation (inline)
192  *
193  * @param sl is a vector of IPv6 addresses composing the Segment List
194  *
195  * @return precomputed rewrite string for encapsulation
196  */
197 static inline u8 *
198 compute_rewrite_encaps (ip6_address_t * sl)
199 {
200   ip6_header_t *iph;
201   ip6_sr_header_t *srh;
202   ip6_address_t *addrp, *this_address;
203   u32 header_length = 0;
204   u8 *rs = NULL;
205
206   header_length = 0;
207   header_length += IPv6_DEFAULT_HEADER_LENGTH;
208   if (vec_len (sl) > 1)
209     {
210       header_length += sizeof (ip6_sr_header_t);
211       header_length += vec_len (sl) * sizeof (ip6_address_t);
212     }
213
214   vec_validate (rs, header_length - 1);
215
216   iph = (ip6_header_t *) rs;
217   iph->ip_version_traffic_class_and_flow_label =
218     clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
219   iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
220   iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
221   iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
222   iph->protocol = IP_PROTOCOL_IPV6;
223   iph->hop_limit = sr_pr_encaps_hop_limit;
224
225   if (vec_len (sl) > 1)
226     {
227       srh = (ip6_sr_header_t *) (iph + 1);
228       iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
229       srh->protocol = IP_PROTOCOL_IPV6;
230       srh->type = ROUTING_HEADER_TYPE_SR;
231       srh->segments_left = vec_len (sl) - 1;
232       srh->last_entry = vec_len (sl) - 1;
233       srh->length = ((sizeof (ip6_sr_header_t) +
234                       (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
235       srh->flags = 0x00;
236       srh->tag = 0x0000;
237       addrp = srh->segments + vec_len (sl) - 1;
238       vec_foreach (this_address, sl)
239       {
240         clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
241                           sizeof (ip6_address_t));
242         addrp--;
243       }
244     }
245   iph->dst_address.as_u64[0] = sl->as_u64[0];
246   iph->dst_address.as_u64[1] = sl->as_u64[1];
247   return rs;
248 }
249
250 /**
251  * @brief SR rewrite string computation for SRH insertion (inline)
252  *
253  * @param sl is a vector of IPv6 addresses composing the Segment List
254  *
255  * @return precomputed rewrite string for SRH insertion
256  */
257 static inline u8 *
258 compute_rewrite_insert (ip6_address_t * sl)
259 {
260   ip6_sr_header_t *srh;
261   ip6_address_t *addrp, *this_address;
262   u32 header_length = 0;
263   u8 *rs = NULL;
264
265   header_length = 0;
266   header_length += sizeof (ip6_sr_header_t);
267   header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
268
269   vec_validate (rs, header_length - 1);
270
271   srh = (ip6_sr_header_t *) rs;
272   srh->type = ROUTING_HEADER_TYPE_SR;
273   srh->segments_left = vec_len (sl);
274   srh->last_entry = vec_len (sl);
275   srh->length = ((sizeof (ip6_sr_header_t) +
276                   ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
277   srh->flags = 0x00;
278   srh->tag = 0x0000;
279   addrp = srh->segments + vec_len (sl);
280   vec_foreach (this_address, sl)
281   {
282     clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
283                       sizeof (ip6_address_t));
284     addrp--;
285   }
286   return rs;
287 }
288
289 /**
290  * @brief SR rewrite string computation for SRH insertion with BSID (inline)
291  *
292  * @param sl is a vector of IPv6 addresses composing the Segment List
293  *
294  * @return precomputed rewrite string for SRH insertion with BSID
295  */
296 static inline u8 *
297 compute_rewrite_bsid (ip6_address_t * sl)
298 {
299   ip6_sr_header_t *srh;
300   ip6_address_t *addrp, *this_address;
301   u32 header_length = 0;
302   u8 *rs = NULL;
303
304   header_length = 0;
305   header_length += sizeof (ip6_sr_header_t);
306   header_length += vec_len (sl) * sizeof (ip6_address_t);
307
308   vec_validate (rs, header_length - 1);
309
310   srh = (ip6_sr_header_t *) rs;
311   srh->type = ROUTING_HEADER_TYPE_SR;
312   srh->segments_left = vec_len (sl) - 1;
313   srh->last_entry = vec_len (sl) - 1;
314   srh->length = ((sizeof (ip6_sr_header_t) +
315                   (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
316   srh->flags = 0x00;
317   srh->tag = 0x0000;
318   addrp = srh->segments + vec_len (sl) - 1;
319   vec_foreach (this_address, sl)
320   {
321     clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
322                       sizeof (ip6_address_t));
323     addrp--;
324   }
325   return rs;
326 }
327
328 /***************************  SR LB helper functions **************************/
329 /**
330  * @brief Creates a Segment List and adds it to an SR policy
331  *
332  * Creates a Segment List and adds it to the SR policy. Notice that the SL are
333  * not necessarily unique. Hence there might be two Segment List within the
334  * same SR Policy with exactly the same segments and same weight.
335  *
336  * @param sr_policy is the SR policy where the SL will be added
337  * @param sl is a vector of IPv6 addresses composing the Segment List
338  * @param weight is the weight of the SegmentList (for load-balancing purposes)
339  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
340  *
341  * @return pointer to the just created segment list
342  */
343 static inline ip6_sr_sl_t *
344 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
345            u8 is_encap)
346 {
347   ip6_sr_main_t *sm = &sr_main;
348   ip6_sr_sl_t *segment_list;
349   sr_policy_fn_registration_t *plugin = 0;
350
351   pool_get (sm->sid_lists, segment_list);
352   clib_memset (segment_list, 0, sizeof (*segment_list));
353
354   vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
355
356   /* Fill in segment list */
357   segment_list->weight =
358     (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
359
360   segment_list->segments = vec_dup (sl);
361
362   if (is_encap)
363     {
364       segment_list->rewrite = compute_rewrite_encaps (sl);
365       segment_list->rewrite_bsid = segment_list->rewrite;
366     }
367   else
368     {
369       segment_list->rewrite = compute_rewrite_insert (sl);
370       segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
371     }
372
373   if (sr_policy->plugin)
374     {
375       plugin =
376         pool_elt_at_index (sm->policy_plugin_functions,
377                            sr_policy->plugin - SR_BEHAVIOR_LAST);
378
379       segment_list->plugin = sr_policy->plugin;
380       segment_list->plugin_mem = sr_policy->plugin_mem;
381
382       plugin->creation (sr_policy);
383     }
384
385   /* Create DPO */
386   dpo_reset (&segment_list->bsid_dpo);
387   dpo_reset (&segment_list->ip6_dpo);
388   dpo_reset (&segment_list->ip4_dpo);
389
390   if (is_encap)
391     {
392       if (!sr_policy->plugin)
393         {
394           dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
395                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
396           dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
397                    DPO_PROTO_IP4, segment_list - sm->sid_lists);
398           dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
399                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
400         }
401       else
402         {
403           dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
404                    segment_list - sm->sid_lists);
405           dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
406                    segment_list - sm->sid_lists);
407           dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
408                    segment_list - sm->sid_lists);
409         }
410     }
411   else
412     {
413       if (!sr_policy->plugin)
414         {
415           dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
416                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
417           dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
418                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
419         }
420       else
421         {
422           dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
423                    segment_list - sm->sid_lists);
424           dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
425                    segment_list - sm->sid_lists);
426         }
427     }
428
429   return segment_list;
430 }
431
432 /**
433  * @brief Updates the Load Balancer after an SR Policy change
434  *
435  * @param sr_policy is the modified SR Policy
436  */
437 static inline void
438 update_lb (ip6_sr_policy_t * sr_policy)
439 {
440   flow_hash_config_t fhc;
441   u32 *sl_index;
442   ip6_sr_sl_t *segment_list;
443   ip6_sr_main_t *sm = &sr_main;
444   load_balance_path_t path;
445   path.path_index = FIB_NODE_INDEX_INVALID;
446   load_balance_path_t *ip4_path_vector = 0;
447   load_balance_path_t *ip6_path_vector = 0;
448   load_balance_path_t *b_path_vector = 0;
449
450   /* In case LB does not exist, create it */
451   if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
452     {
453       fib_prefix_t pfx = {
454         .fp_proto = FIB_PROTOCOL_IP6,
455         .fp_len = 128,
456         .fp_addr = {
457                     .ip6 = sr_policy->bsid,
458                     }
459       };
460
461       /* Add FIB entry for BSID */
462       fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
463                                             FIB_PROTOCOL_IP6);
464
465       dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
466                load_balance_create (0, DPO_PROTO_IP6, fhc));
467
468       dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
469                load_balance_create (0, DPO_PROTO_IP6, fhc));
470
471       /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
472       fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473                                                           sr_policy->fib_table),
474                                           &pfx, FIB_SOURCE_SR,
475                                           FIB_ENTRY_FLAG_EXCLUSIVE,
476                                           &sr_policy->bsid_dpo);
477
478       fib_table_entry_special_dpo_update (sm->fib_table_ip6,
479                                           &pfx,
480                                           FIB_SOURCE_SR,
481                                           FIB_ENTRY_FLAG_EXCLUSIVE,
482                                           &sr_policy->ip6_dpo);
483
484       if (sr_policy->is_encap)
485         {
486           dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
487                    load_balance_create (0, DPO_PROTO_IP4, fhc));
488
489           fib_table_entry_special_dpo_update (sm->fib_table_ip4,
490                                               &pfx,
491                                               FIB_SOURCE_SR,
492                                               FIB_ENTRY_FLAG_EXCLUSIVE,
493                                               &sr_policy->ip4_dpo);
494         }
495
496     }
497
498   /* Create the LB path vector */
499   vec_foreach (sl_index, sr_policy->segments_lists)
500   {
501     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
502     path.path_dpo = segment_list->bsid_dpo;
503     path.path_weight = segment_list->weight;
504     vec_add1 (b_path_vector, path);
505     path.path_dpo = segment_list->ip6_dpo;
506     vec_add1 (ip6_path_vector, path);
507     if (sr_policy->is_encap)
508       {
509         path.path_dpo = segment_list->ip4_dpo;
510         vec_add1 (ip4_path_vector, path);
511       }
512   }
513
514   /* Update LB multipath */
515   load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
516                                  LOAD_BALANCE_FLAG_NONE);
517   load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
518                                  LOAD_BALANCE_FLAG_NONE);
519   if (sr_policy->is_encap)
520     load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
521                                    LOAD_BALANCE_FLAG_NONE);
522
523   /* Cleanup */
524   vec_free (b_path_vector);
525   vec_free (ip6_path_vector);
526   vec_free (ip4_path_vector);
527 }
528
529 /**
530  * @brief Updates the Replicate DPO after an SR Policy change
531  *
532  * @param sr_policy is the modified SR Policy (type spray)
533  */
534 static inline void
535 update_replicate (ip6_sr_policy_t * sr_policy)
536 {
537   u32 *sl_index;
538   ip6_sr_sl_t *segment_list;
539   ip6_sr_main_t *sm = &sr_main;
540   load_balance_path_t path;
541   path.path_index = FIB_NODE_INDEX_INVALID;
542   load_balance_path_t *b_path_vector = 0;
543   load_balance_path_t *ip6_path_vector = 0;
544   load_balance_path_t *ip4_path_vector = 0;
545
546   /* In case LB does not exist, create it */
547   if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
548     {
549       dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
550                DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
551
552       dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
553                DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
554
555       /* Update FIB entry's DPO to point to SR without LB */
556       fib_prefix_t pfx = {
557         .fp_proto = FIB_PROTOCOL_IP6,
558         .fp_len = 128,
559         .fp_addr = {
560                     .ip6 = sr_policy->bsid,
561                     }
562       };
563       fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
564                                                           sr_policy->fib_table),
565                                           &pfx, FIB_SOURCE_SR,
566                                           FIB_ENTRY_FLAG_EXCLUSIVE,
567                                           &sr_policy->bsid_dpo);
568
569       fib_table_entry_special_dpo_update (sm->fib_table_ip6,
570                                           &pfx,
571                                           FIB_SOURCE_SR,
572                                           FIB_ENTRY_FLAG_EXCLUSIVE,
573                                           &sr_policy->ip6_dpo);
574
575       if (sr_policy->is_encap)
576         {
577           dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
578                    replicate_create (0, DPO_PROTO_IP4));
579
580           fib_table_entry_special_dpo_update (sm->fib_table_ip4,
581                                               &pfx,
582                                               FIB_SOURCE_SR,
583                                               FIB_ENTRY_FLAG_EXCLUSIVE,
584                                               &sr_policy->ip4_dpo);
585         }
586
587     }
588
589   /* Create the replicate path vector */
590   path.path_weight = 1;
591   vec_foreach (sl_index, sr_policy->segments_lists)
592   {
593     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
594     path.path_dpo = segment_list->bsid_dpo;
595     vec_add1 (b_path_vector, path);
596     path.path_dpo = segment_list->ip6_dpo;
597     vec_add1 (ip6_path_vector, path);
598     if (sr_policy->is_encap)
599       {
600         path.path_dpo = segment_list->ip4_dpo;
601         vec_add1 (ip4_path_vector, path);
602       }
603   }
604
605   /* Update replicate multipath */
606   replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
607   replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
608   if (sr_policy->is_encap)
609     replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
610 }
611
612 /******************************* SR rewrite API *******************************/
613 /* Three functions for handling sr policies:
614  *   -> sr_policy_add
615  *   -> sr_policy_del
616  *   -> sr_policy_mod
617  * All of them are API. CLI function on sr_policy_command_fn                  */
618
619 /**
620  * @brief Create a new SR policy
621  *
622  * @param bsid is the bindingSID of the SR Policy
623  * @param segments is a vector of IPv6 address composing the segment list
624  * @param weight is the weight of the sid list. optional.
625  * @param behavior is the behavior of the SR policy. (default//spray)
626  * @param fib_table is the VRF where to install the FIB entry for the BSID
627  * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
628  *
629  * @return 0 if correct, else error
630  */
631 int
632 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
633                u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
634                u16 plugin, void *ls_plugin_mem)
635 {
636   ip6_sr_main_t *sm = &sr_main;
637   ip6_sr_policy_t *sr_policy = 0;
638   uword *p;
639
640   /* Search for existing keys (BSID) */
641   p = mhash_get (&sm->sr_policies_index_hash, bsid);
642   if (p)
643     {
644       /* Add SR policy that already exists; complain */
645       return -12;
646     }
647
648   /* Search collision in FIB entries */
649   /* Explanation: It might be possible that some other entity has already
650    * created a route for the BSID. This in theory is impossible, but in
651    * practise we could see it. Assert it and scream if needed */
652   fib_prefix_t pfx = {
653     .fp_proto = FIB_PROTOCOL_IP6,
654     .fp_len = 128,
655     .fp_addr = {
656                 .ip6 = *bsid,
657                 }
658   };
659
660   /* Lookup the FIB index associated to the table selected */
661   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
662                                   (fib_table != (u32) ~ 0 ? fib_table : 0));
663   if (fib_index == ~0)
664     return -13;
665
666   /* Lookup whether there exists an entry for the BSID */
667   fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
668   if (FIB_NODE_INDEX_INVALID != fei)
669     return -12;                 //There is an entry for such lookup
670
671   /* Add an SR policy object */
672   pool_get (sm->sr_policies, sr_policy);
673   clib_memset (sr_policy, 0, sizeof (*sr_policy));
674   clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
675   sr_policy->type = behavior;
676   sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0);      //Is default FIB 0 ?
677   sr_policy->is_encap = is_encap;
678
679   if (plugin)
680     {
681       sr_policy->plugin = plugin;
682       sr_policy->plugin_mem = ls_plugin_mem;
683     }
684
685   /* Copy the key */
686   mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
687              NULL);
688
689   /* Create a segment list and add the index to the SR policy */
690   create_sl (sr_policy, segments, weight, is_encap);
691
692   /* If FIB doesnt exist, create them */
693   if (sm->fib_table_ip6 == (u32) ~ 0)
694     {
695       sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
696                                                      FIB_SOURCE_SR,
697                                                      "SRv6 steering of IP6 prefixes through BSIDs");
698       sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
699                                                      FIB_SOURCE_SR,
700                                                      "SRv6 steering of IP4 prefixes through BSIDs");
701     }
702
703   /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
704   if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
705     update_lb (sr_policy);
706   else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
707     update_replicate (sr_policy);
708   return 0;
709 }
710
711 /**
712  * @brief Delete a SR policy
713  *
714  * @param bsid is the bindingSID of the SR Policy
715  * @param index is the index of the SR policy
716  *
717  * @return 0 if correct, else error
718  */
719 int
720 sr_policy_del (ip6_address_t * bsid, u32 index)
721 {
722   ip6_sr_main_t *sm = &sr_main;
723   ip6_sr_policy_t *sr_policy = 0;
724   ip6_sr_sl_t *segment_list;
725   u32 *sl_index;
726   uword *p;
727
728   if (bsid)
729     {
730       p = mhash_get (&sm->sr_policies_index_hash, bsid);
731       if (p)
732         sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
733       else
734         return -1;
735     }
736   else
737     {
738       sr_policy = pool_elt_at_index (sm->sr_policies, index);
739       if (!sr_policy)
740         return -1;
741     }
742
743   /* Remove BindingSID FIB entry */
744   fib_prefix_t pfx = {
745     .fp_proto = FIB_PROTOCOL_IP6,
746     .fp_len = 128,
747     .fp_addr = {
748                 .ip6 = sr_policy->bsid,
749                 }
750     ,
751   };
752
753   fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
754                                                   sr_policy->fib_table),
755                                   &pfx, FIB_SOURCE_SR);
756
757   fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
758
759   if (sr_policy->is_encap)
760     fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
761
762   if (dpo_id_is_valid (&sr_policy->bsid_dpo))
763     {
764       dpo_reset (&sr_policy->bsid_dpo);
765       dpo_reset (&sr_policy->ip4_dpo);
766       dpo_reset (&sr_policy->ip6_dpo);
767     }
768
769   /* Clean SID Lists */
770   vec_foreach (sl_index, sr_policy->segments_lists)
771   {
772     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
773     vec_free (segment_list->segments);
774     vec_free (segment_list->rewrite);
775     if (!sr_policy->is_encap)
776       vec_free (segment_list->rewrite_bsid);
777     pool_put_index (sm->sid_lists, *sl_index);
778   }
779
780   if (sr_policy->plugin)
781     {
782       sr_policy_fn_registration_t *plugin = 0;
783
784       plugin =
785         pool_elt_at_index (sm->policy_plugin_functions,
786                            sr_policy->plugin - SR_BEHAVIOR_LAST);
787
788       plugin->removal (sr_policy);
789       sr_policy->plugin = 0;
790       sr_policy->plugin_mem = NULL;
791     }
792
793   /* Remove SR policy entry */
794   mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
795   pool_put (sm->sr_policies, sr_policy);
796
797   /* If FIB empty unlock it */
798   if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
799     {
800       fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
801       fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
802       sm->fib_table_ip6 = (u32) ~ 0;
803       sm->fib_table_ip4 = (u32) ~ 0;
804     }
805
806   return 0;
807 }
808
809 /**
810  * @brief Modify an existing SR policy
811  *
812  * The possible modifications are adding a new Segment List, modifying an
813  * existing Segment List (modify the weight only) and delete a given
814  * Segment List from the SR Policy.
815  *
816  * @param bsid is the bindingSID of the SR Policy
817  * @param index is the index of the SR policy
818  * @param fib_table is the VRF where to install the FIB entry for the BSID
819  * @param operation is the operation to perform (among the top ones)
820  * @param segments is a vector of IPv6 address composing the segment list
821  * @param sl_index is the index of the Segment List to modify/delete
822  * @param weight is the weight of the sid list. optional.
823  * @param is_encap Mode. Encapsulation or SRH insertion.
824  *
825  * @return 0 if correct, else error
826  */
827 int
828 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
829                u8 operation, ip6_address_t * segments, u32 sl_index,
830                u32 weight)
831 {
832   ip6_sr_main_t *sm = &sr_main;
833   ip6_sr_policy_t *sr_policy = 0;
834   ip6_sr_sl_t *segment_list;
835   u32 *sl_index_iterate;
836   uword *p;
837
838   if (bsid)
839     {
840       p = mhash_get (&sm->sr_policies_index_hash, bsid);
841       if (p)
842         sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
843       else
844         return -1;
845     }
846   else
847     {
848       sr_policy = pool_elt_at_index (sm->sr_policies, index);
849       if (!sr_policy)
850         return -1;
851     }
852
853   if (operation == 1)           /* Add SR List to an existing SR policy */
854     {
855       /* Create the new SL */
856       segment_list =
857         create_sl (sr_policy, segments, weight, sr_policy->is_encap);
858
859       /* Create a new LB DPO */
860       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
861         update_lb (sr_policy);
862       else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
863         update_replicate (sr_policy);
864     }
865   else if (operation == 2)      /* Delete SR List from an existing SR policy */
866     {
867       /* Check that currently there are more than one SID list */
868       if (vec_len (sr_policy->segments_lists) == 1)
869         return -21;
870
871       /* Check that the SR list does exist and is assigned to the sr policy */
872       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
873         if (*sl_index_iterate == sl_index)
874         break;
875
876       if (*sl_index_iterate != sl_index)
877         return -22;
878
879       /* Remove the lucky SR list that is being kicked out */
880       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
881       vec_free (segment_list->segments);
882       vec_free (segment_list->rewrite);
883       if (!sr_policy->is_encap)
884         vec_free (segment_list->rewrite_bsid);
885       pool_put_index (sm->sid_lists, sl_index);
886       vec_del1 (sr_policy->segments_lists,
887                 sl_index_iterate - sr_policy->segments_lists);
888
889       /* Create a new LB DPO */
890       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
891         update_lb (sr_policy);
892       else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
893         update_replicate (sr_policy);
894     }
895   else if (operation == 3)      /* Modify the weight of an existing SR List */
896     {
897       /* Find the corresponding SL */
898       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
899         if (*sl_index_iterate == sl_index)
900         break;
901
902       if (*sl_index_iterate != sl_index)
903         return -32;
904
905       /* Change the weight */
906       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
907       segment_list->weight = weight;
908
909       /* Update LB */
910       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
911         update_lb (sr_policy);
912     }
913   else                          /* Incorrect op. */
914     return -1;
915
916   return 0;
917 }
918
919 /**
920  * @brief CLI for 'sr policies' command family
921  */
922 static clib_error_t *
923 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
924                       vlib_cli_command_t * cmd)
925 {
926   ip6_sr_main_t *sm = &sr_main;
927   int rv = -1;
928   char is_del = 0, is_add = 0, is_mod = 0;
929   char policy_set = 0;
930   ip6_address_t bsid, next_address;
931   u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
932   u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
933   ip6_address_t *segments = 0, *this_seg;
934   u8 operation = 0;
935   char is_encap = 1;
936   char is_spray = 0;
937   u16 behavior = 0;
938   void *ls_plugin_mem = 0;
939
940   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
941     {
942       if (!is_add && !is_mod && !is_del && unformat (input, "add"))
943         is_add = 1;
944       else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
945         is_del = 1;
946       else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
947         is_mod = 1;
948       else if (!policy_set
949                && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
950         policy_set = 1;
951       else if (!is_add && !policy_set
952                && unformat (input, "index %d", &sr_policy_index))
953         policy_set = 1;
954       else if (unformat (input, "weight %d", &weight));
955       else
956         if (unformat (input, "next %U", unformat_ip6_address, &next_address))
957         {
958           vec_add2 (segments, this_seg, 1);
959           clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
960                             sizeof (*this_seg));
961         }
962       else if (unformat (input, "add sl"))
963         operation = 1;
964       else if (unformat (input, "del sl index %d", &sl_index))
965         operation = 2;
966       else if (unformat (input, "mod sl index %d", &sl_index))
967         operation = 3;
968       else if (fib_table == (u32) ~ 0
969                && unformat (input, "fib-table %d", &fib_table));
970       else if (unformat (input, "encap"))
971         is_encap = 1;
972       else if (unformat (input, "insert"))
973         is_encap = 0;
974       else if (unformat (input, "spray"))
975         is_spray = 1;
976       else if (!behavior && unformat (input, "behavior"))
977         {
978           sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
979           sr_policy_fn_registration_t **plugin_it = 0;
980
981           /* *INDENT-OFF* */
982           pool_foreach (plugin, sm->policy_plugin_functions,
983             {
984               vec_add1 (vec_plugins, plugin);
985             });
986           /* *INDENT-ON* */
987
988           vec_foreach (plugin_it, vec_plugins)
989           {
990             if (unformat
991                 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
992               {
993                 behavior = (*plugin_it)->sr_policy_function_number;
994                 break;
995               }
996           }
997
998           if (!behavior)
999             {
1000               return clib_error_return (0, "Invalid behavior");
1001             }
1002         }
1003       else
1004         break;
1005     }
1006
1007   if (!is_add && !is_mod && !is_del)
1008     return clib_error_return (0, "Incorrect CLI");
1009
1010   if (!policy_set)
1011     return clib_error_return (0, "No SR policy BSID or index specified");
1012
1013   if (is_add)
1014     {
1015       if (behavior && vec_len (segments) == 0)
1016         {
1017           vec_add2 (segments, this_seg, 1);
1018           clib_memset (this_seg, 0, sizeof (*this_seg));
1019         }
1020
1021       if (vec_len (segments) == 0)
1022         return clib_error_return (0, "No Segment List specified");
1023
1024       rv = sr_policy_add (&bsid, segments, weight,
1025                           (is_spray ? SR_POLICY_TYPE_SPRAY :
1026                            SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1027                           behavior, ls_plugin_mem);
1028
1029       vec_free (segments);
1030     }
1031   else if (is_del)
1032     rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1033                         sr_policy_index);
1034   else if (is_mod)
1035     {
1036       if (!operation)
1037         return clib_error_return (0, "No SL modification specified");
1038       if (operation != 1 && sl_index == (u32) ~ 0)
1039         return clib_error_return (0, "No Segment List index specified");
1040       if (operation == 1 && vec_len (segments) == 0)
1041         return clib_error_return (0, "No Segment List specified");
1042       if (operation == 3 && weight == (u32) ~ 0)
1043         return clib_error_return (0, "No new weight for the SL specified");
1044
1045       rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1046                           sr_policy_index, fib_table, operation, segments,
1047                           sl_index, weight);
1048
1049       if (segments)
1050         vec_free (segments);
1051     }
1052
1053   switch (rv)
1054     {
1055     case 0:
1056       break;
1057     case 1:
1058       return 0;
1059     case -12:
1060       return clib_error_return (0,
1061                                 "There is already a FIB entry for the BindingSID address.\n"
1062                                 "The SR policy could not be created.");
1063     case -13:
1064       return clib_error_return (0, "The specified FIB table does not exist.");
1065     case -21:
1066       return clib_error_return (0,
1067                                 "The selected SR policy only contains ONE segment list. "
1068                                 "Please remove the SR policy instead");
1069     case -22:
1070       return clib_error_return (0,
1071                                 "Could not delete the segment list. "
1072                                 "It is not associated with that SR policy.");
1073     case -32:
1074       return clib_error_return (0,
1075                                 "Could not modify the segment list. "
1076                                 "The given SL is not associated with such SR policy.");
1077     default:
1078       return clib_error_return (0, "BUG: sr policy returns %d", rv);
1079     }
1080   return 0;
1081 }
1082
1083 /* *INDENT-OFF* */
1084 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1085   .path = "sr policy",
1086   .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1087     "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1088   .long_help =
1089     "Manipulation of SR policies.\n"
1090     "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1091     "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1092     "Segment Routing policies might be of type encapsulation or srh insertion\n"
1093     "Each SR policy will be associated with a unique BindingSID.\n"
1094     "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1095     "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1096     "The add command will create a SR policy with its first segment list (sl)\n"
1097     "The mod command allows you to add, remove, or modify the existing segment lists\n"
1098     "within an SR policy.\n"
1099     "The del command allows you to delete a SR policy along with all its associated\n"
1100     "SID lists.\n",
1101   .function = sr_policy_command_fn,
1102 };
1103 /* *INDENT-ON* */
1104
1105 /**
1106  * @brief CLI to display onscreen all the SR policies
1107  */
1108 static clib_error_t *
1109 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1110                              vlib_cli_command_t * cmd)
1111 {
1112   ip6_sr_main_t *sm = &sr_main;
1113   u32 *sl_index;
1114   ip6_sr_sl_t *segment_list = 0;
1115   ip6_sr_policy_t *sr_policy = 0;
1116   ip6_sr_policy_t **vec_policies = 0;
1117   ip6_address_t *addr;
1118   u8 *s;
1119   int i = 0;
1120
1121   vlib_cli_output (vm, "SR policies:");
1122
1123   /* *INDENT-OFF* */
1124   pool_foreach  (sr_policy, sm->sr_policies,
1125                 {vec_add1 (vec_policies, sr_policy); } );
1126   /* *INDENT-ON* */
1127
1128   vec_foreach_index (i, vec_policies)
1129   {
1130     sr_policy = vec_policies[i];
1131     vlib_cli_output (vm, "[%u].-\tBSID: %U",
1132                      (u32) (sr_policy - sm->sr_policies),
1133                      format_ip6_address, &sr_policy->bsid);
1134     vlib_cli_output (vm, "\tBehavior: %s",
1135                      (sr_policy->is_encap ? "Encapsulation" :
1136                       "SRH insertion"));
1137     vlib_cli_output (vm, "\tType: %s",
1138                      (sr_policy->type ==
1139                       SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1140     vlib_cli_output (vm, "\tFIB table: %u",
1141                      (sr_policy->fib_table !=
1142                       (u32) ~ 0 ? sr_policy->fib_table : 0));
1143     vlib_cli_output (vm, "\tSegment Lists:");
1144     vec_foreach (sl_index, sr_policy->segments_lists)
1145     {
1146       s = NULL;
1147       s = format (s, "\t[%u].- ", *sl_index);
1148       segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1149       s = format (s, "< ");
1150       vec_foreach (addr, segment_list->segments)
1151       {
1152         s = format (s, "%U, ", format_ip6_address, addr);
1153       }
1154       s = format (s, "\b\b > ");
1155       s = format (s, "weight: %u", segment_list->weight);
1156       vlib_cli_output (vm, "  %v", s);
1157     }
1158     vlib_cli_output (vm, "-----------");
1159   }
1160   return 0;
1161 }
1162
1163 /* *INDENT-OFF* */
1164 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1165   .path = "show sr policies",
1166   .short_help = "show sr policies",
1167   .function = show_sr_policies_command_fn,
1168 };
1169 /* *INDENT-ON* */
1170
1171 /**
1172  * @brief CLI to display onscreen the SR encaps source addr
1173  */
1174 static clib_error_t *
1175 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1176                                   vlib_cli_command_t * cmd)
1177 {
1178   vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1179                    sr_get_encaps_source ());
1180
1181   return 0;
1182 }
1183
1184 /* *INDENT-OFF* */
1185 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1186   .path = "show sr encaps source addr",
1187   .short_help = "show sr encaps source addr",
1188   .function = show_sr_encaps_source_command_fn,
1189 };
1190 /* *INDENT-ON* */
1191
1192 /*************************** SR rewrite graph node ****************************/
1193 /**
1194  * @brief Trace for the SR Policy Rewrite graph node
1195  */
1196 static u8 *
1197 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1198 {
1199   //TODO
1200   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1201   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1202   sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1203
1204   s = format
1205     (s, "SR-policy-rewrite: src %U dst %U",
1206      format_ip6_address, &t->src, format_ip6_address, &t->dst);
1207
1208   return s;
1209 }
1210
1211 /**
1212  * @brief IPv6 encapsulation processing as per RFC2473
1213  */
1214 static_always_inline void
1215 encaps_processing_v6 (vlib_node_runtime_t * node,
1216                       vlib_buffer_t * b0,
1217                       ip6_header_t * ip0, ip6_header_t * ip0_encap)
1218 {
1219   u32 new_l0;
1220
1221   ip0_encap->hop_limit -= 1;
1222   new_l0 =
1223     ip0->payload_length + sizeof (ip6_header_t) +
1224     clib_net_to_host_u16 (ip0_encap->payload_length);
1225   ip0->payload_length = clib_host_to_net_u16 (new_l0);
1226   ip0->ip_version_traffic_class_and_flow_label =
1227     ip0_encap->ip_version_traffic_class_and_flow_label;
1228 }
1229
1230 /**
1231  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1232  */
1233 static uword
1234 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1235                           vlib_frame_t * from_frame)
1236 {
1237   ip6_sr_main_t *sm = &sr_main;
1238   u32 n_left_from, next_index, *from, *to_next;
1239
1240   from = vlib_frame_vector_args (from_frame);
1241   n_left_from = from_frame->n_vectors;
1242
1243   next_index = node->cached_next_index;
1244
1245   int encap_pkts = 0, bsid_pkts = 0;
1246
1247   while (n_left_from > 0)
1248     {
1249       u32 n_left_to_next;
1250
1251       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1252
1253       /* Quad - Loop */
1254       while (n_left_from >= 8 && n_left_to_next >= 4)
1255         {
1256           u32 bi0, bi1, bi2, bi3;
1257           vlib_buffer_t *b0, *b1, *b2, *b3;
1258           u32 next0, next1, next2, next3;
1259           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1260           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1261           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1262           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1263
1264           /* Prefetch next iteration. */
1265           {
1266             vlib_buffer_t *p4, *p5, *p6, *p7;
1267
1268             p4 = vlib_get_buffer (vm, from[4]);
1269             p5 = vlib_get_buffer (vm, from[5]);
1270             p6 = vlib_get_buffer (vm, from[6]);
1271             p7 = vlib_get_buffer (vm, from[7]);
1272
1273             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1274             vlib_prefetch_buffer_header (p4, LOAD);
1275             vlib_prefetch_buffer_header (p5, LOAD);
1276             vlib_prefetch_buffer_header (p6, LOAD);
1277             vlib_prefetch_buffer_header (p7, LOAD);
1278
1279             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1280             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1281             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1282             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1283           }
1284
1285           to_next[0] = bi0 = from[0];
1286           to_next[1] = bi1 = from[1];
1287           to_next[2] = bi2 = from[2];
1288           to_next[3] = bi3 = from[3];
1289           from += 4;
1290           to_next += 4;
1291           n_left_from -= 4;
1292           n_left_to_next -= 4;
1293
1294           b0 = vlib_get_buffer (vm, bi0);
1295           b1 = vlib_get_buffer (vm, bi1);
1296           b2 = vlib_get_buffer (vm, bi2);
1297           b3 = vlib_get_buffer (vm, bi3);
1298
1299           sl0 =
1300             pool_elt_at_index (sm->sid_lists,
1301                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1302           sl1 =
1303             pool_elt_at_index (sm->sid_lists,
1304                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1305           sl2 =
1306             pool_elt_at_index (sm->sid_lists,
1307                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1308           sl3 =
1309             pool_elt_at_index (sm->sid_lists,
1310                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1311
1312           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1313                   vec_len (sl0->rewrite));
1314           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1315                   vec_len (sl1->rewrite));
1316           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1317                   vec_len (sl2->rewrite));
1318           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1319                   vec_len (sl3->rewrite));
1320
1321           ip0_encap = vlib_buffer_get_current (b0);
1322           ip1_encap = vlib_buffer_get_current (b1);
1323           ip2_encap = vlib_buffer_get_current (b2);
1324           ip3_encap = vlib_buffer_get_current (b3);
1325
1326           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1327                             sl0->rewrite, vec_len (sl0->rewrite));
1328           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1329                             sl1->rewrite, vec_len (sl1->rewrite));
1330           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1331                             sl2->rewrite, vec_len (sl2->rewrite));
1332           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1333                             sl3->rewrite, vec_len (sl3->rewrite));
1334
1335           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1336           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1337           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1338           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1339
1340           ip0 = vlib_buffer_get_current (b0);
1341           ip1 = vlib_buffer_get_current (b1);
1342           ip2 = vlib_buffer_get_current (b2);
1343           ip3 = vlib_buffer_get_current (b3);
1344
1345           encaps_processing_v6 (node, b0, ip0, ip0_encap);
1346           encaps_processing_v6 (node, b1, ip1, ip1_encap);
1347           encaps_processing_v6 (node, b2, ip2, ip2_encap);
1348           encaps_processing_v6 (node, b3, ip3, ip3_encap);
1349
1350           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1351             {
1352               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1353                 {
1354                   sr_policy_rewrite_trace_t *tr =
1355                     vlib_add_trace (vm, node, b0, sizeof (*tr));
1356                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1357                                     sizeof (tr->src.as_u8));
1358                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1359                                     sizeof (tr->dst.as_u8));
1360                 }
1361
1362               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1363                 {
1364                   sr_policy_rewrite_trace_t *tr =
1365                     vlib_add_trace (vm, node, b1, sizeof (*tr));
1366                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1367                                     sizeof (tr->src.as_u8));
1368                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1369                                     sizeof (tr->dst.as_u8));
1370                 }
1371
1372               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1373                 {
1374                   sr_policy_rewrite_trace_t *tr =
1375                     vlib_add_trace (vm, node, b2, sizeof (*tr));
1376                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1377                                     sizeof (tr->src.as_u8));
1378                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1379                                     sizeof (tr->dst.as_u8));
1380                 }
1381
1382               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1383                 {
1384                   sr_policy_rewrite_trace_t *tr =
1385                     vlib_add_trace (vm, node, b3, sizeof (*tr));
1386                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1387                                     sizeof (tr->src.as_u8));
1388                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1389                                     sizeof (tr->dst.as_u8));
1390                 }
1391             }
1392
1393           encap_pkts += 4;
1394           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1395                                            n_left_to_next, bi0, bi1, bi2, bi3,
1396                                            next0, next1, next2, next3);
1397         }
1398
1399       /* Single loop for potentially the last three packets */
1400       while (n_left_from > 0 && n_left_to_next > 0)
1401         {
1402           u32 bi0;
1403           vlib_buffer_t *b0;
1404           ip6_header_t *ip0 = 0, *ip0_encap = 0;
1405           ip6_sr_sl_t *sl0;
1406           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1407
1408           bi0 = from[0];
1409           to_next[0] = bi0;
1410           from += 1;
1411           to_next += 1;
1412           n_left_from -= 1;
1413           n_left_to_next -= 1;
1414           b0 = vlib_get_buffer (vm, bi0);
1415
1416           sl0 =
1417             pool_elt_at_index (sm->sid_lists,
1418                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1419           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1420                   vec_len (sl0->rewrite));
1421
1422           ip0_encap = vlib_buffer_get_current (b0);
1423
1424           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1425                             sl0->rewrite, vec_len (sl0->rewrite));
1426           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1427
1428           ip0 = vlib_buffer_get_current (b0);
1429
1430           encaps_processing_v6 (node, b0, ip0, ip0_encap);
1431
1432           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1433               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1434             {
1435               sr_policy_rewrite_trace_t *tr =
1436                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1437               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1438                                 sizeof (tr->src.as_u8));
1439               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1440                                 sizeof (tr->dst.as_u8));
1441             }
1442
1443           encap_pkts++;
1444           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1445                                            n_left_to_next, bi0, next0);
1446         }
1447
1448       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1449     }
1450
1451   /* Update counters */
1452   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1453                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1454                                encap_pkts);
1455   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1456                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1457                                bsid_pkts);
1458
1459   return from_frame->n_vectors;
1460 }
1461
1462 /* *INDENT-OFF* */
1463 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1464   .function = sr_policy_rewrite_encaps,
1465   .name = "sr-pl-rewrite-encaps",
1466   .vector_size = sizeof (u32),
1467   .format_trace = format_sr_policy_rewrite_trace,
1468   .type = VLIB_NODE_TYPE_INTERNAL,
1469   .n_errors = SR_POLICY_REWRITE_N_ERROR,
1470   .error_strings = sr_policy_rewrite_error_strings,
1471   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1472   .next_nodes = {
1473 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1474     foreach_sr_policy_rewrite_next
1475 #undef _
1476   },
1477 };
1478 /* *INDENT-ON* */
1479
1480 /**
1481  * @brief IPv4 encapsulation processing as per RFC2473
1482  */
1483 static_always_inline void
1484 encaps_processing_v4 (vlib_node_runtime_t * node,
1485                       vlib_buffer_t * b0,
1486                       ip6_header_t * ip0, ip4_header_t * ip0_encap)
1487 {
1488   u32 new_l0;
1489   ip6_sr_header_t *sr0;
1490
1491   u32 checksum0;
1492
1493   /* Inner IPv4: Decrement TTL & update checksum */
1494   ip0_encap->ttl -= 1;
1495   checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1496   checksum0 += checksum0 >= 0xffff;
1497   ip0_encap->checksum = checksum0;
1498
1499   /* Outer IPv6: Update length, FL, proto */
1500   new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1501   ip0->payload_length = clib_host_to_net_u16 (new_l0);
1502   ip0->ip_version_traffic_class_and_flow_label =
1503     clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1504                           ((ip0_encap->tos & 0xFF) << 20));
1505   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1506     {
1507       sr0 = (void *) (ip0 + 1);
1508       sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1509     }
1510   else
1511     ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1512 }
1513
1514 /**
1515  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1516  */
1517 static uword
1518 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1519                              vlib_frame_t * from_frame)
1520 {
1521   ip6_sr_main_t *sm = &sr_main;
1522   u32 n_left_from, next_index, *from, *to_next;
1523
1524   from = vlib_frame_vector_args (from_frame);
1525   n_left_from = from_frame->n_vectors;
1526
1527   next_index = node->cached_next_index;
1528
1529   int encap_pkts = 0, bsid_pkts = 0;
1530
1531   while (n_left_from > 0)
1532     {
1533       u32 n_left_to_next;
1534
1535       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1536
1537       /* Quad - Loop */
1538       while (n_left_from >= 8 && n_left_to_next >= 4)
1539         {
1540           u32 bi0, bi1, bi2, bi3;
1541           vlib_buffer_t *b0, *b1, *b2, *b3;
1542           u32 next0, next1, next2, next3;
1543           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1544           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1545           ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1546           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1547
1548           /* Prefetch next iteration. */
1549           {
1550             vlib_buffer_t *p4, *p5, *p6, *p7;
1551
1552             p4 = vlib_get_buffer (vm, from[4]);
1553             p5 = vlib_get_buffer (vm, from[5]);
1554             p6 = vlib_get_buffer (vm, from[6]);
1555             p7 = vlib_get_buffer (vm, from[7]);
1556
1557             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1558             vlib_prefetch_buffer_header (p4, LOAD);
1559             vlib_prefetch_buffer_header (p5, LOAD);
1560             vlib_prefetch_buffer_header (p6, LOAD);
1561             vlib_prefetch_buffer_header (p7, LOAD);
1562
1563             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1564             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1565             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1566             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1567           }
1568
1569           to_next[0] = bi0 = from[0];
1570           to_next[1] = bi1 = from[1];
1571           to_next[2] = bi2 = from[2];
1572           to_next[3] = bi3 = from[3];
1573           from += 4;
1574           to_next += 4;
1575           n_left_from -= 4;
1576           n_left_to_next -= 4;
1577
1578           b0 = vlib_get_buffer (vm, bi0);
1579           b1 = vlib_get_buffer (vm, bi1);
1580           b2 = vlib_get_buffer (vm, bi2);
1581           b3 = vlib_get_buffer (vm, bi3);
1582
1583           sl0 =
1584             pool_elt_at_index (sm->sid_lists,
1585                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1586           sl1 =
1587             pool_elt_at_index (sm->sid_lists,
1588                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1589           sl2 =
1590             pool_elt_at_index (sm->sid_lists,
1591                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1592           sl3 =
1593             pool_elt_at_index (sm->sid_lists,
1594                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1595           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1596                   vec_len (sl0->rewrite));
1597           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1598                   vec_len (sl1->rewrite));
1599           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1600                   vec_len (sl2->rewrite));
1601           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1602                   vec_len (sl3->rewrite));
1603
1604           ip0_encap = vlib_buffer_get_current (b0);
1605           ip1_encap = vlib_buffer_get_current (b1);
1606           ip2_encap = vlib_buffer_get_current (b2);
1607           ip3_encap = vlib_buffer_get_current (b3);
1608
1609           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1610                             sl0->rewrite, vec_len (sl0->rewrite));
1611           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1612                             sl1->rewrite, vec_len (sl1->rewrite));
1613           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1614                             sl2->rewrite, vec_len (sl2->rewrite));
1615           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1616                             sl3->rewrite, vec_len (sl3->rewrite));
1617
1618           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1619           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1620           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1621           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1622
1623           ip0 = vlib_buffer_get_current (b0);
1624           ip1 = vlib_buffer_get_current (b1);
1625           ip2 = vlib_buffer_get_current (b2);
1626           ip3 = vlib_buffer_get_current (b3);
1627
1628           encaps_processing_v4 (node, b0, ip0, ip0_encap);
1629           encaps_processing_v4 (node, b1, ip1, ip1_encap);
1630           encaps_processing_v4 (node, b2, ip2, ip2_encap);
1631           encaps_processing_v4 (node, b3, ip3, ip3_encap);
1632
1633           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1634             {
1635               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1636                 {
1637                   sr_policy_rewrite_trace_t *tr =
1638                     vlib_add_trace (vm, node, b0, sizeof (*tr));
1639                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1640                                     sizeof (tr->src.as_u8));
1641                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1642                                     sizeof (tr->dst.as_u8));
1643                 }
1644
1645               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1646                 {
1647                   sr_policy_rewrite_trace_t *tr =
1648                     vlib_add_trace (vm, node, b1, sizeof (*tr));
1649                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1650                                     sizeof (tr->src.as_u8));
1651                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1652                                     sizeof (tr->dst.as_u8));
1653                 }
1654
1655               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1656                 {
1657                   sr_policy_rewrite_trace_t *tr =
1658                     vlib_add_trace (vm, node, b2, sizeof (*tr));
1659                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1660                                     sizeof (tr->src.as_u8));
1661                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1662                                     sizeof (tr->dst.as_u8));
1663                 }
1664
1665               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1666                 {
1667                   sr_policy_rewrite_trace_t *tr =
1668                     vlib_add_trace (vm, node, b3, sizeof (*tr));
1669                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1670                                     sizeof (tr->src.as_u8));
1671                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1672                                     sizeof (tr->dst.as_u8));
1673                 }
1674             }
1675
1676           encap_pkts += 4;
1677           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1678                                            n_left_to_next, bi0, bi1, bi2, bi3,
1679                                            next0, next1, next2, next3);
1680         }
1681
1682       /* Single loop for potentially the last three packets */
1683       while (n_left_from > 0 && n_left_to_next > 0)
1684         {
1685           u32 bi0;
1686           vlib_buffer_t *b0;
1687           ip6_header_t *ip0 = 0;
1688           ip4_header_t *ip0_encap = 0;
1689           ip6_sr_sl_t *sl0;
1690           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1691
1692           bi0 = from[0];
1693           to_next[0] = bi0;
1694           from += 1;
1695           to_next += 1;
1696           n_left_from -= 1;
1697           n_left_to_next -= 1;
1698           b0 = vlib_get_buffer (vm, bi0);
1699
1700           sl0 =
1701             pool_elt_at_index (sm->sid_lists,
1702                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1703           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1704                   vec_len (sl0->rewrite));
1705
1706           ip0_encap = vlib_buffer_get_current (b0);
1707
1708           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1709                             sl0->rewrite, vec_len (sl0->rewrite));
1710           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1711
1712           ip0 = vlib_buffer_get_current (b0);
1713
1714           encaps_processing_v4 (node, b0, ip0, ip0_encap);
1715
1716           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1717               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1718             {
1719               sr_policy_rewrite_trace_t *tr =
1720                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1721               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1722                                 sizeof (tr->src.as_u8));
1723               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1724                                 sizeof (tr->dst.as_u8));
1725             }
1726
1727           encap_pkts++;
1728           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1729                                            n_left_to_next, bi0, next0);
1730         }
1731
1732       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1733     }
1734
1735   /* Update counters */
1736   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1737                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1738                                encap_pkts);
1739   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1740                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1741                                bsid_pkts);
1742
1743   return from_frame->n_vectors;
1744 }
1745
1746 /* *INDENT-OFF* */
1747 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1748   .function = sr_policy_rewrite_encaps_v4,
1749   .name = "sr-pl-rewrite-encaps-v4",
1750   .vector_size = sizeof (u32),
1751   .format_trace = format_sr_policy_rewrite_trace,
1752   .type = VLIB_NODE_TYPE_INTERNAL,
1753   .n_errors = SR_POLICY_REWRITE_N_ERROR,
1754   .error_strings = sr_policy_rewrite_error_strings,
1755   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1756   .next_nodes = {
1757 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1758     foreach_sr_policy_rewrite_next
1759 #undef _
1760   },
1761 };
1762 /* *INDENT-ON* */
1763
1764 always_inline u32
1765 ip_flow_hash (void *data)
1766 {
1767   ip4_header_t *iph = (ip4_header_t *) data;
1768
1769   if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1770     return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1771   else
1772     return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1773 }
1774
1775 always_inline u64
1776 mac_to_u64 (u8 * m)
1777 {
1778   return (*((u64 *) m) & 0xffffffffffff);
1779 }
1780
1781 always_inline u32
1782 l2_flow_hash (vlib_buffer_t * b0)
1783 {
1784   ethernet_header_t *eh;
1785   u64 a, b, c;
1786   uword is_ip, eh_size;
1787   u16 eh_type;
1788
1789   eh = vlib_buffer_get_current (b0);
1790   eh_type = clib_net_to_host_u16 (eh->type);
1791   eh_size = ethernet_buffer_header_size (b0);
1792
1793   is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1794
1795   /* since we have 2 cache lines, use them */
1796   if (is_ip)
1797     a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1798   else
1799     a = eh->type;
1800
1801   b = mac_to_u64 ((u8 *) eh->dst_address);
1802   c = mac_to_u64 ((u8 *) eh->src_address);
1803   hash_mix64 (a, b, c);
1804
1805   return (u32) c;
1806 }
1807
1808 /**
1809  * @brief Graph node for applying a SR policy into a L2 frame
1810  */
1811 static uword
1812 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1813                              vlib_frame_t * from_frame)
1814 {
1815   ip6_sr_main_t *sm = &sr_main;
1816   u32 n_left_from, next_index, *from, *to_next;
1817
1818   from = vlib_frame_vector_args (from_frame);
1819   n_left_from = from_frame->n_vectors;
1820
1821   next_index = node->cached_next_index;
1822
1823   int encap_pkts = 0, bsid_pkts = 0;
1824
1825   while (n_left_from > 0)
1826     {
1827       u32 n_left_to_next;
1828
1829       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1830
1831       /* Quad - Loop */
1832       while (n_left_from >= 8 && n_left_to_next >= 4)
1833         {
1834           u32 bi0, bi1, bi2, bi3;
1835           vlib_buffer_t *b0, *b1, *b2, *b3;
1836           u32 next0, next1, next2, next3;
1837           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1838           ethernet_header_t *en0, *en1, *en2, *en3;
1839           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1840           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1841           ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1842           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1843
1844           /* Prefetch next iteration. */
1845           {
1846             vlib_buffer_t *p4, *p5, *p6, *p7;
1847
1848             p4 = vlib_get_buffer (vm, from[4]);
1849             p5 = vlib_get_buffer (vm, from[5]);
1850             p6 = vlib_get_buffer (vm, from[6]);
1851             p7 = vlib_get_buffer (vm, from[7]);
1852
1853             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1854             vlib_prefetch_buffer_header (p4, LOAD);
1855             vlib_prefetch_buffer_header (p5, LOAD);
1856             vlib_prefetch_buffer_header (p6, LOAD);
1857             vlib_prefetch_buffer_header (p7, LOAD);
1858
1859             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1860             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1861             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1862             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1863           }
1864
1865           to_next[0] = bi0 = from[0];
1866           to_next[1] = bi1 = from[1];
1867           to_next[2] = bi2 = from[2];
1868           to_next[3] = bi3 = from[3];
1869           from += 4;
1870           to_next += 4;
1871           n_left_from -= 4;
1872           n_left_to_next -= 4;
1873
1874           b0 = vlib_get_buffer (vm, bi0);
1875           b1 = vlib_get_buffer (vm, bi1);
1876           b2 = vlib_get_buffer (vm, bi2);
1877           b3 = vlib_get_buffer (vm, bi3);
1878
1879           sp0 = pool_elt_at_index (sm->sr_policies,
1880                                    sm->sw_iface_sr_policies[vnet_buffer
1881                                                             (b0)->sw_if_index
1882                                                             [VLIB_RX]]);
1883
1884           sp1 = pool_elt_at_index (sm->sr_policies,
1885                                    sm->sw_iface_sr_policies[vnet_buffer
1886                                                             (b1)->sw_if_index
1887                                                             [VLIB_RX]]);
1888
1889           sp2 = pool_elt_at_index (sm->sr_policies,
1890                                    sm->sw_iface_sr_policies[vnet_buffer
1891                                                             (b2)->sw_if_index
1892                                                             [VLIB_RX]]);
1893
1894           sp3 = pool_elt_at_index (sm->sr_policies,
1895                                    sm->sw_iface_sr_policies[vnet_buffer
1896                                                             (b3)->sw_if_index
1897                                                             [VLIB_RX]]);
1898
1899           if (vec_len (sp0->segments_lists) == 1)
1900             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1901           else
1902             {
1903               vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1904               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1905                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1906                                      (vec_len (sp0->segments_lists) - 1))];
1907             }
1908
1909           if (vec_len (sp1->segments_lists) == 1)
1910             vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1911           else
1912             {
1913               vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1914               vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1915                 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1916                                      (vec_len (sp1->segments_lists) - 1))];
1917             }
1918
1919           if (vec_len (sp2->segments_lists) == 1)
1920             vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1921           else
1922             {
1923               vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1924               vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1925                 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1926                                      (vec_len (sp2->segments_lists) - 1))];
1927             }
1928
1929           if (vec_len (sp3->segments_lists) == 1)
1930             vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1931           else
1932             {
1933               vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1934               vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1935                 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1936                                      (vec_len (sp3->segments_lists) - 1))];
1937             }
1938
1939           sl0 =
1940             pool_elt_at_index (sm->sid_lists,
1941                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1942           sl1 =
1943             pool_elt_at_index (sm->sid_lists,
1944                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1945           sl2 =
1946             pool_elt_at_index (sm->sid_lists,
1947                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1948           sl3 =
1949             pool_elt_at_index (sm->sid_lists,
1950                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1951
1952           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1953                   vec_len (sl0->rewrite));
1954           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1955                   vec_len (sl1->rewrite));
1956           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1957                   vec_len (sl2->rewrite));
1958           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1959                   vec_len (sl3->rewrite));
1960
1961           en0 = vlib_buffer_get_current (b0);
1962           en1 = vlib_buffer_get_current (b1);
1963           en2 = vlib_buffer_get_current (b2);
1964           en3 = vlib_buffer_get_current (b3);
1965
1966           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1967                             sl0->rewrite, vec_len (sl0->rewrite));
1968           clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1969                             sl1->rewrite, vec_len (sl1->rewrite));
1970           clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1971                             sl2->rewrite, vec_len (sl2->rewrite));
1972           clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1973                             sl3->rewrite, vec_len (sl3->rewrite));
1974
1975           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1976           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1977           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1978           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1979
1980           ip0 = vlib_buffer_get_current (b0);
1981           ip1 = vlib_buffer_get_current (b1);
1982           ip2 = vlib_buffer_get_current (b2);
1983           ip3 = vlib_buffer_get_current (b3);
1984
1985           ip0->payload_length =
1986             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1987           ip1->payload_length =
1988             clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1989           ip2->payload_length =
1990             clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1991           ip3->payload_length =
1992             clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1993
1994           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1995             {
1996               sr0 = (void *) (ip0 + 1);
1997               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
1998             }
1999           else
2000             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2001
2002           if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2003             {
2004               sr1 = (void *) (ip1 + 1);
2005               sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2006             }
2007           else
2008             ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2009
2010           if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2011             {
2012               sr2 = (void *) (ip2 + 1);
2013               sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2014             }
2015           else
2016             ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2017
2018           if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2019             {
2020               sr3 = (void *) (ip3 + 1);
2021               sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2022             }
2023           else
2024             ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2025
2026           /* Which Traffic class and flow label do I set ? */
2027           //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2028
2029           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2030             {
2031               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2032                 {
2033                   sr_policy_rewrite_trace_t *tr =
2034                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2035                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2036                                     sizeof (tr->src.as_u8));
2037                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2038                                     sizeof (tr->dst.as_u8));
2039                 }
2040
2041               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2042                 {
2043                   sr_policy_rewrite_trace_t *tr =
2044                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2045                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2046                                     sizeof (tr->src.as_u8));
2047                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2048                                     sizeof (tr->dst.as_u8));
2049                 }
2050
2051               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2052                 {
2053                   sr_policy_rewrite_trace_t *tr =
2054                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2055                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2056                                     sizeof (tr->src.as_u8));
2057                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2058                                     sizeof (tr->dst.as_u8));
2059                 }
2060
2061               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2062                 {
2063                   sr_policy_rewrite_trace_t *tr =
2064                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2065                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2066                                     sizeof (tr->src.as_u8));
2067                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2068                                     sizeof (tr->dst.as_u8));
2069                 }
2070             }
2071
2072           encap_pkts += 4;
2073           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2074                                            n_left_to_next, bi0, bi1, bi2, bi3,
2075                                            next0, next1, next2, next3);
2076         }
2077
2078       /* Single loop for potentially the last three packets */
2079       while (n_left_from > 0 && n_left_to_next > 0)
2080         {
2081           u32 bi0;
2082           vlib_buffer_t *b0;
2083           ip6_header_t *ip0 = 0;
2084           ip6_sr_header_t *sr0;
2085           ethernet_header_t *en0;
2086           ip6_sr_policy_t *sp0;
2087           ip6_sr_sl_t *sl0;
2088           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2089
2090           bi0 = from[0];
2091           to_next[0] = bi0;
2092           from += 1;
2093           to_next += 1;
2094           n_left_from -= 1;
2095           n_left_to_next -= 1;
2096           b0 = vlib_get_buffer (vm, bi0);
2097
2098           /* Find the SR policy */
2099           sp0 = pool_elt_at_index (sm->sr_policies,
2100                                    sm->sw_iface_sr_policies[vnet_buffer
2101                                                             (b0)->sw_if_index
2102                                                             [VLIB_RX]]);
2103
2104           /* In case there is more than one SL, LB among them */
2105           if (vec_len (sp0->segments_lists) == 1)
2106             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2107           else
2108             {
2109               vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2110               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2111                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2112                                      (vec_len (sp0->segments_lists) - 1))];
2113             }
2114           sl0 =
2115             pool_elt_at_index (sm->sid_lists,
2116                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2117           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2118                   vec_len (sl0->rewrite));
2119
2120           en0 = vlib_buffer_get_current (b0);
2121
2122           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2123                             sl0->rewrite, vec_len (sl0->rewrite));
2124
2125           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2126
2127           ip0 = vlib_buffer_get_current (b0);
2128
2129           ip0->payload_length =
2130             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2131
2132           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2133             {
2134               sr0 = (void *) (ip0 + 1);
2135               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2136             }
2137           else
2138             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2139
2140           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2141               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2142             {
2143               sr_policy_rewrite_trace_t *tr =
2144                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2145               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2146                                 sizeof (tr->src.as_u8));
2147               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2148                                 sizeof (tr->dst.as_u8));
2149             }
2150
2151           encap_pkts++;
2152           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2153                                            n_left_to_next, bi0, next0);
2154         }
2155
2156       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2157     }
2158
2159   /* Update counters */
2160   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2161                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2162                                encap_pkts);
2163   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2164                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2165                                bsid_pkts);
2166
2167   return from_frame->n_vectors;
2168 }
2169
2170 /* *INDENT-OFF* */
2171 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2172   .function = sr_policy_rewrite_encaps_l2,
2173   .name = "sr-pl-rewrite-encaps-l2",
2174   .vector_size = sizeof (u32),
2175   .format_trace = format_sr_policy_rewrite_trace,
2176   .type = VLIB_NODE_TYPE_INTERNAL,
2177   .n_errors = SR_POLICY_REWRITE_N_ERROR,
2178   .error_strings = sr_policy_rewrite_error_strings,
2179   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2180   .next_nodes = {
2181 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2182     foreach_sr_policy_rewrite_next
2183 #undef _
2184   },
2185 };
2186 /* *INDENT-ON* */
2187
2188 /**
2189  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2190  */
2191 static uword
2192 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2193                           vlib_frame_t * from_frame)
2194 {
2195   ip6_sr_main_t *sm = &sr_main;
2196   u32 n_left_from, next_index, *from, *to_next;
2197
2198   from = vlib_frame_vector_args (from_frame);
2199   n_left_from = from_frame->n_vectors;
2200
2201   next_index = node->cached_next_index;
2202
2203   int insert_pkts = 0, bsid_pkts = 0;
2204
2205   while (n_left_from > 0)
2206     {
2207       u32 n_left_to_next;
2208
2209       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2210
2211       /* Quad - Loop */
2212       while (n_left_from >= 8 && n_left_to_next >= 4)
2213         {
2214           u32 bi0, bi1, bi2, bi3;
2215           vlib_buffer_t *b0, *b1, *b2, *b3;
2216           u32 next0, next1, next2, next3;
2217           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2218           ip6_header_t *ip0, *ip1, *ip2, *ip3;
2219           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2220           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2221           u16 new_l0, new_l1, new_l2, new_l3;
2222
2223           /* Prefetch next iteration. */
2224           {
2225             vlib_buffer_t *p4, *p5, *p6, *p7;
2226
2227             p4 = vlib_get_buffer (vm, from[4]);
2228             p5 = vlib_get_buffer (vm, from[5]);
2229             p6 = vlib_get_buffer (vm, from[6]);
2230             p7 = vlib_get_buffer (vm, from[7]);
2231
2232             /* Prefetch the buffer header and packet for the N+2 loop iteration */
2233             vlib_prefetch_buffer_header (p4, LOAD);
2234             vlib_prefetch_buffer_header (p5, LOAD);
2235             vlib_prefetch_buffer_header (p6, LOAD);
2236             vlib_prefetch_buffer_header (p7, LOAD);
2237
2238             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2239             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2240             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2241             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2242           }
2243
2244           to_next[0] = bi0 = from[0];
2245           to_next[1] = bi1 = from[1];
2246           to_next[2] = bi2 = from[2];
2247           to_next[3] = bi3 = from[3];
2248           from += 4;
2249           to_next += 4;
2250           n_left_from -= 4;
2251           n_left_to_next -= 4;
2252
2253           b0 = vlib_get_buffer (vm, bi0);
2254           b1 = vlib_get_buffer (vm, bi1);
2255           b2 = vlib_get_buffer (vm, bi2);
2256           b3 = vlib_get_buffer (vm, bi3);
2257
2258           sl0 =
2259             pool_elt_at_index (sm->sid_lists,
2260                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2261           sl1 =
2262             pool_elt_at_index (sm->sid_lists,
2263                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2264           sl2 =
2265             pool_elt_at_index (sm->sid_lists,
2266                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2267           sl3 =
2268             pool_elt_at_index (sm->sid_lists,
2269                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2270           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2271                   vec_len (sl0->rewrite));
2272           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2273                   vec_len (sl1->rewrite));
2274           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2275                   vec_len (sl2->rewrite));
2276           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2277                   vec_len (sl3->rewrite));
2278
2279           ip0 = vlib_buffer_get_current (b0);
2280           ip1 = vlib_buffer_get_current (b1);
2281           ip2 = vlib_buffer_get_current (b2);
2282           ip3 = vlib_buffer_get_current (b3);
2283
2284           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2285             sr0 =
2286               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2287                                    ip6_ext_header_len (ip0 + 1));
2288           else
2289             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2290
2291           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2292             sr1 =
2293               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2294                                    ip6_ext_header_len (ip1 + 1));
2295           else
2296             sr1 = (ip6_sr_header_t *) (ip1 + 1);
2297
2298           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2299             sr2 =
2300               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2301                                    ip6_ext_header_len (ip2 + 1));
2302           else
2303             sr2 = (ip6_sr_header_t *) (ip2 + 1);
2304
2305           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2306             sr3 =
2307               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2308                                    ip6_ext_header_len (ip3 + 1));
2309           else
2310             sr3 = (ip6_sr_header_t *) (ip3 + 1);
2311
2312           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2313                             (void *) sr0 - (void *) ip0);
2314           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2315                             (void *) sr1 - (void *) ip1);
2316           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2317                             (void *) sr2 - (void *) ip2);
2318           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2319                             (void *) sr3 - (void *) ip3);
2320
2321           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2322                             sl0->rewrite, vec_len (sl0->rewrite));
2323           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2324                             sl1->rewrite, vec_len (sl1->rewrite));
2325           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2326                             sl2->rewrite, vec_len (sl2->rewrite));
2327           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2328                             sl3->rewrite, vec_len (sl3->rewrite));
2329
2330           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2331           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2332           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2333           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2334
2335           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2336           ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2337           ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2338           ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2339
2340           ip0->hop_limit -= 1;
2341           ip1->hop_limit -= 1;
2342           ip2->hop_limit -= 1;
2343           ip3->hop_limit -= 1;
2344
2345           new_l0 =
2346             clib_net_to_host_u16 (ip0->payload_length) +
2347             vec_len (sl0->rewrite);
2348           new_l1 =
2349             clib_net_to_host_u16 (ip1->payload_length) +
2350             vec_len (sl1->rewrite);
2351           new_l2 =
2352             clib_net_to_host_u16 (ip2->payload_length) +
2353             vec_len (sl2->rewrite);
2354           new_l3 =
2355             clib_net_to_host_u16 (ip3->payload_length) +
2356             vec_len (sl3->rewrite);
2357
2358           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2359           ip1->payload_length = clib_host_to_net_u16 (new_l1);
2360           ip2->payload_length = clib_host_to_net_u16 (new_l2);
2361           ip3->payload_length = clib_host_to_net_u16 (new_l3);
2362
2363           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2364           sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2365           sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2366           sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2367
2368           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2369           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2370           sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2371           sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2372           sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2373           sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2374           sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2375           sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2376
2377           ip0->dst_address.as_u64[0] =
2378             (sr0->segments + sr0->segments_left)->as_u64[0];
2379           ip0->dst_address.as_u64[1] =
2380             (sr0->segments + sr0->segments_left)->as_u64[1];
2381           ip1->dst_address.as_u64[0] =
2382             (sr1->segments + sr1->segments_left)->as_u64[0];
2383           ip1->dst_address.as_u64[1] =
2384             (sr1->segments + sr1->segments_left)->as_u64[1];
2385           ip2->dst_address.as_u64[0] =
2386             (sr2->segments + sr2->segments_left)->as_u64[0];
2387           ip2->dst_address.as_u64[1] =
2388             (sr2->segments + sr2->segments_left)->as_u64[1];
2389           ip3->dst_address.as_u64[0] =
2390             (sr3->segments + sr3->segments_left)->as_u64[0];
2391           ip3->dst_address.as_u64[1] =
2392             (sr3->segments + sr3->segments_left)->as_u64[1];
2393
2394           ip6_ext_header_t *ip_ext;
2395           if (ip0 + 1 == (void *) sr0)
2396             {
2397               sr0->protocol = ip0->protocol;
2398               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2399             }
2400           else
2401             {
2402               ip_ext = (void *) (ip0 + 1);
2403               sr0->protocol = ip_ext->next_hdr;
2404               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2405             }
2406
2407           if (ip1 + 1 == (void *) sr1)
2408             {
2409               sr1->protocol = ip1->protocol;
2410               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2411             }
2412           else
2413             {
2414               ip_ext = (void *) (ip2 + 1);
2415               sr2->protocol = ip_ext->next_hdr;
2416               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2417             }
2418
2419           if (ip2 + 1 == (void *) sr2)
2420             {
2421               sr2->protocol = ip2->protocol;
2422               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2423             }
2424           else
2425             {
2426               ip_ext = (void *) (ip2 + 1);
2427               sr2->protocol = ip_ext->next_hdr;
2428               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2429             }
2430
2431           if (ip3 + 1 == (void *) sr3)
2432             {
2433               sr3->protocol = ip3->protocol;
2434               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2435             }
2436           else
2437             {
2438               ip_ext = (void *) (ip3 + 1);
2439               sr3->protocol = ip_ext->next_hdr;
2440               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2441             }
2442
2443           insert_pkts += 4;
2444
2445           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2446             {
2447               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2448                 {
2449                   sr_policy_rewrite_trace_t *tr =
2450                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2451                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2452                                     sizeof (tr->src.as_u8));
2453                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2454                                     sizeof (tr->dst.as_u8));
2455                 }
2456
2457               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2458                 {
2459                   sr_policy_rewrite_trace_t *tr =
2460                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2461                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2462                                     sizeof (tr->src.as_u8));
2463                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2464                                     sizeof (tr->dst.as_u8));
2465                 }
2466
2467               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2468                 {
2469                   sr_policy_rewrite_trace_t *tr =
2470                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2471                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2472                                     sizeof (tr->src.as_u8));
2473                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2474                                     sizeof (tr->dst.as_u8));
2475                 }
2476
2477               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2478                 {
2479                   sr_policy_rewrite_trace_t *tr =
2480                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2481                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2482                                     sizeof (tr->src.as_u8));
2483                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2484                                     sizeof (tr->dst.as_u8));
2485                 }
2486             }
2487
2488           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2489                                            n_left_to_next, bi0, bi1, bi2, bi3,
2490                                            next0, next1, next2, next3);
2491         }
2492
2493       /* Single loop for potentially the last three packets */
2494       while (n_left_from > 0 && n_left_to_next > 0)
2495         {
2496           u32 bi0;
2497           vlib_buffer_t *b0;
2498           ip6_header_t *ip0 = 0;
2499           ip6_sr_header_t *sr0 = 0;
2500           ip6_sr_sl_t *sl0;
2501           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2502           u16 new_l0 = 0;
2503
2504           bi0 = from[0];
2505           to_next[0] = bi0;
2506           from += 1;
2507           to_next += 1;
2508           n_left_from -= 1;
2509           n_left_to_next -= 1;
2510
2511           b0 = vlib_get_buffer (vm, bi0);
2512           sl0 =
2513             pool_elt_at_index (sm->sid_lists,
2514                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2515           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2516                   vec_len (sl0->rewrite));
2517
2518           ip0 = vlib_buffer_get_current (b0);
2519
2520           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2521             sr0 =
2522               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2523                                    ip6_ext_header_len (ip0 + 1));
2524           else
2525             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2526
2527           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2528                             (void *) sr0 - (void *) ip0);
2529           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2530                             sl0->rewrite, vec_len (sl0->rewrite));
2531
2532           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2533
2534           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2535           ip0->hop_limit -= 1;
2536           new_l0 =
2537             clib_net_to_host_u16 (ip0->payload_length) +
2538             vec_len (sl0->rewrite);
2539           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2540
2541           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2542           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2543           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2544
2545           ip0->dst_address.as_u64[0] =
2546             (sr0->segments + sr0->segments_left)->as_u64[0];
2547           ip0->dst_address.as_u64[1] =
2548             (sr0->segments + sr0->segments_left)->as_u64[1];
2549
2550           if (ip0 + 1 == (void *) sr0)
2551             {
2552               sr0->protocol = ip0->protocol;
2553               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2554             }
2555           else
2556             {
2557               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2558               sr0->protocol = ip_ext->next_hdr;
2559               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2560             }
2561
2562           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2563               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2564             {
2565               sr_policy_rewrite_trace_t *tr =
2566                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2567               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2568                                 sizeof (tr->src.as_u8));
2569               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2570                                 sizeof (tr->dst.as_u8));
2571             }
2572
2573           insert_pkts++;
2574
2575           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2576                                            n_left_to_next, bi0, next0);
2577         }
2578
2579       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2580     }
2581
2582   /* Update counters */
2583   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2584                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2585                                insert_pkts);
2586   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2587                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2588                                bsid_pkts);
2589   return from_frame->n_vectors;
2590 }
2591
2592 /* *INDENT-OFF* */
2593 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2594   .function = sr_policy_rewrite_insert,
2595   .name = "sr-pl-rewrite-insert",
2596   .vector_size = sizeof (u32),
2597   .format_trace = format_sr_policy_rewrite_trace,
2598   .type = VLIB_NODE_TYPE_INTERNAL,
2599   .n_errors = SR_POLICY_REWRITE_N_ERROR,
2600   .error_strings = sr_policy_rewrite_error_strings,
2601   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2602   .next_nodes = {
2603 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2604     foreach_sr_policy_rewrite_next
2605 #undef _
2606   },
2607 };
2608 /* *INDENT-ON* */
2609
2610 /**
2611  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2612  */
2613 static uword
2614 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2615                             vlib_frame_t * from_frame)
2616 {
2617   ip6_sr_main_t *sm = &sr_main;
2618   u32 n_left_from, next_index, *from, *to_next;
2619
2620   from = vlib_frame_vector_args (from_frame);
2621   n_left_from = from_frame->n_vectors;
2622
2623   next_index = node->cached_next_index;
2624
2625   int insert_pkts = 0, bsid_pkts = 0;
2626
2627   while (n_left_from > 0)
2628     {
2629       u32 n_left_to_next;
2630
2631       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2632
2633       /* Quad - Loop */
2634       while (n_left_from >= 8 && n_left_to_next >= 4)
2635         {
2636           u32 bi0, bi1, bi2, bi3;
2637           vlib_buffer_t *b0, *b1, *b2, *b3;
2638           u32 next0, next1, next2, next3;
2639           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2640           ip6_header_t *ip0, *ip1, *ip2, *ip3;
2641           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2642           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2643           u16 new_l0, new_l1, new_l2, new_l3;
2644
2645           /* Prefetch next iteration. */
2646           {
2647             vlib_buffer_t *p4, *p5, *p6, *p7;
2648
2649             p4 = vlib_get_buffer (vm, from[4]);
2650             p5 = vlib_get_buffer (vm, from[5]);
2651             p6 = vlib_get_buffer (vm, from[6]);
2652             p7 = vlib_get_buffer (vm, from[7]);
2653
2654             /* Prefetch the buffer header and packet for the N+2 loop iteration */
2655             vlib_prefetch_buffer_header (p4, LOAD);
2656             vlib_prefetch_buffer_header (p5, LOAD);
2657             vlib_prefetch_buffer_header (p6, LOAD);
2658             vlib_prefetch_buffer_header (p7, LOAD);
2659
2660             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2661             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2662             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2663             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2664           }
2665
2666           to_next[0] = bi0 = from[0];
2667           to_next[1] = bi1 = from[1];
2668           to_next[2] = bi2 = from[2];
2669           to_next[3] = bi3 = from[3];
2670           from += 4;
2671           to_next += 4;
2672           n_left_from -= 4;
2673           n_left_to_next -= 4;
2674
2675           b0 = vlib_get_buffer (vm, bi0);
2676           b1 = vlib_get_buffer (vm, bi1);
2677           b2 = vlib_get_buffer (vm, bi2);
2678           b3 = vlib_get_buffer (vm, bi3);
2679
2680           sl0 =
2681             pool_elt_at_index (sm->sid_lists,
2682                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2683           sl1 =
2684             pool_elt_at_index (sm->sid_lists,
2685                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2686           sl2 =
2687             pool_elt_at_index (sm->sid_lists,
2688                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2689           sl3 =
2690             pool_elt_at_index (sm->sid_lists,
2691                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2692           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2693                   vec_len (sl0->rewrite_bsid));
2694           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2695                   vec_len (sl1->rewrite_bsid));
2696           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2697                   vec_len (sl2->rewrite_bsid));
2698           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2699                   vec_len (sl3->rewrite_bsid));
2700
2701           ip0 = vlib_buffer_get_current (b0);
2702           ip1 = vlib_buffer_get_current (b1);
2703           ip2 = vlib_buffer_get_current (b2);
2704           ip3 = vlib_buffer_get_current (b3);
2705
2706           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2707             sr0 =
2708               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2709                                    ip6_ext_header_len (ip0 + 1));
2710           else
2711             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2712
2713           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2714             sr1 =
2715               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2716                                    ip6_ext_header_len (ip1 + 1));
2717           else
2718             sr1 = (ip6_sr_header_t *) (ip1 + 1);
2719
2720           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2721             sr2 =
2722               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2723                                    ip6_ext_header_len (ip2 + 1));
2724           else
2725             sr2 = (ip6_sr_header_t *) (ip2 + 1);
2726
2727           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2728             sr3 =
2729               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2730                                    ip6_ext_header_len (ip3 + 1));
2731           else
2732             sr3 = (ip6_sr_header_t *) (ip3 + 1);
2733
2734           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2735                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
2736           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2737                             (u8 *) ip1, (void *) sr1 - (void *) ip1);
2738           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2739                             (u8 *) ip2, (void *) sr2 - (void *) ip2);
2740           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2741                             (u8 *) ip3, (void *) sr3 - (void *) ip3);
2742
2743           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2744                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2745           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2746                             sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2747           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2748                             sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2749           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2750                             sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2751
2752           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2753           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2754           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2755           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2756
2757           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2758           ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2759           ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2760           ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2761
2762           ip0->hop_limit -= 1;
2763           ip1->hop_limit -= 1;
2764           ip2->hop_limit -= 1;
2765           ip3->hop_limit -= 1;
2766
2767           new_l0 =
2768             clib_net_to_host_u16 (ip0->payload_length) +
2769             vec_len (sl0->rewrite_bsid);
2770           new_l1 =
2771             clib_net_to_host_u16 (ip1->payload_length) +
2772             vec_len (sl1->rewrite_bsid);
2773           new_l2 =
2774             clib_net_to_host_u16 (ip2->payload_length) +
2775             vec_len (sl2->rewrite_bsid);
2776           new_l3 =
2777             clib_net_to_host_u16 (ip3->payload_length) +
2778             vec_len (sl3->rewrite_bsid);
2779
2780           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2781           ip1->payload_length = clib_host_to_net_u16 (new_l1);
2782           ip2->payload_length = clib_host_to_net_u16 (new_l2);
2783           ip3->payload_length = clib_host_to_net_u16 (new_l3);
2784
2785           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2786           sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2787           sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2788           sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2789
2790           ip0->dst_address.as_u64[0] =
2791             (sr0->segments + sr0->segments_left)->as_u64[0];
2792           ip0->dst_address.as_u64[1] =
2793             (sr0->segments + sr0->segments_left)->as_u64[1];
2794           ip1->dst_address.as_u64[0] =
2795             (sr1->segments + sr1->segments_left)->as_u64[0];
2796           ip1->dst_address.as_u64[1] =
2797             (sr1->segments + sr1->segments_left)->as_u64[1];
2798           ip2->dst_address.as_u64[0] =
2799             (sr2->segments + sr2->segments_left)->as_u64[0];
2800           ip2->dst_address.as_u64[1] =
2801             (sr2->segments + sr2->segments_left)->as_u64[1];
2802           ip3->dst_address.as_u64[0] =
2803             (sr3->segments + sr3->segments_left)->as_u64[0];
2804           ip3->dst_address.as_u64[1] =
2805             (sr3->segments + sr3->segments_left)->as_u64[1];
2806
2807           ip6_ext_header_t *ip_ext;
2808           if (ip0 + 1 == (void *) sr0)
2809             {
2810               sr0->protocol = ip0->protocol;
2811               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2812             }
2813           else
2814             {
2815               ip_ext = (void *) (ip0 + 1);
2816               sr0->protocol = ip_ext->next_hdr;
2817               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2818             }
2819
2820           if (ip1 + 1 == (void *) sr1)
2821             {
2822               sr1->protocol = ip1->protocol;
2823               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2824             }
2825           else
2826             {
2827               ip_ext = (void *) (ip2 + 1);
2828               sr2->protocol = ip_ext->next_hdr;
2829               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2830             }
2831
2832           if (ip2 + 1 == (void *) sr2)
2833             {
2834               sr2->protocol = ip2->protocol;
2835               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2836             }
2837           else
2838             {
2839               ip_ext = (void *) (ip2 + 1);
2840               sr2->protocol = ip_ext->next_hdr;
2841               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2842             }
2843
2844           if (ip3 + 1 == (void *) sr3)
2845             {
2846               sr3->protocol = ip3->protocol;
2847               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2848             }
2849           else
2850             {
2851               ip_ext = (void *) (ip3 + 1);
2852               sr3->protocol = ip_ext->next_hdr;
2853               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2854             }
2855
2856           insert_pkts += 4;
2857
2858           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2859             {
2860               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2861                 {
2862                   sr_policy_rewrite_trace_t *tr =
2863                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2864                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2865                                     sizeof (tr->src.as_u8));
2866                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2867                                     sizeof (tr->dst.as_u8));
2868                 }
2869
2870               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2871                 {
2872                   sr_policy_rewrite_trace_t *tr =
2873                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2874                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2875                                     sizeof (tr->src.as_u8));
2876                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2877                                     sizeof (tr->dst.as_u8));
2878                 }
2879
2880               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2881                 {
2882                   sr_policy_rewrite_trace_t *tr =
2883                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2884                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2885                                     sizeof (tr->src.as_u8));
2886                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2887                                     sizeof (tr->dst.as_u8));
2888                 }
2889
2890               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2891                 {
2892                   sr_policy_rewrite_trace_t *tr =
2893                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2894                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2895                                     sizeof (tr->src.as_u8));
2896                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2897                                     sizeof (tr->dst.as_u8));
2898                 }
2899             }
2900
2901           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2902                                            n_left_to_next, bi0, bi1, bi2, bi3,
2903                                            next0, next1, next2, next3);
2904         }
2905
2906       /* Single loop for potentially the last three packets */
2907       while (n_left_from > 0 && n_left_to_next > 0)
2908         {
2909           u32 bi0;
2910           vlib_buffer_t *b0;
2911           ip6_header_t *ip0 = 0;
2912           ip6_sr_header_t *sr0 = 0;
2913           ip6_sr_sl_t *sl0;
2914           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2915           u16 new_l0 = 0;
2916
2917           bi0 = from[0];
2918           to_next[0] = bi0;
2919           from += 1;
2920           to_next += 1;
2921           n_left_from -= 1;
2922           n_left_to_next -= 1;
2923
2924           b0 = vlib_get_buffer (vm, bi0);
2925           sl0 =
2926             pool_elt_at_index (sm->sid_lists,
2927                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2928           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929                   vec_len (sl0->rewrite_bsid));
2930
2931           ip0 = vlib_buffer_get_current (b0);
2932
2933           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2934             sr0 =
2935               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2936                                    ip6_ext_header_len (ip0 + 1));
2937           else
2938             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2939
2940           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2941                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
2942           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2943                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2944
2945           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2946
2947           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2948           ip0->hop_limit -= 1;
2949           new_l0 =
2950             clib_net_to_host_u16 (ip0->payload_length) +
2951             vec_len (sl0->rewrite_bsid);
2952           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2953
2954           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2955
2956           ip0->dst_address.as_u64[0] =
2957             (sr0->segments + sr0->segments_left)->as_u64[0];
2958           ip0->dst_address.as_u64[1] =
2959             (sr0->segments + sr0->segments_left)->as_u64[1];
2960
2961           if (ip0 + 1 == (void *) sr0)
2962             {
2963               sr0->protocol = ip0->protocol;
2964               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2965             }
2966           else
2967             {
2968               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2969               sr0->protocol = ip_ext->next_hdr;
2970               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2971             }
2972
2973           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2974               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2975             {
2976               sr_policy_rewrite_trace_t *tr =
2977                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2978               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2979                                 sizeof (tr->src.as_u8));
2980               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2981                                 sizeof (tr->dst.as_u8));
2982             }
2983
2984           insert_pkts++;
2985
2986           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2987                                            n_left_to_next, bi0, next0);
2988         }
2989
2990       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2991     }
2992
2993   /* Update counters */
2994   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2995                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2996                                insert_pkts);
2997   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2998                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2999                                bsid_pkts);
3000   return from_frame->n_vectors;
3001 }
3002
3003 /* *INDENT-OFF* */
3004 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3005   .function = sr_policy_rewrite_b_insert,
3006   .name = "sr-pl-rewrite-b-insert",
3007   .vector_size = sizeof (u32),
3008   .format_trace = format_sr_policy_rewrite_trace,
3009   .type = VLIB_NODE_TYPE_INTERNAL,
3010   .n_errors = SR_POLICY_REWRITE_N_ERROR,
3011   .error_strings = sr_policy_rewrite_error_strings,
3012   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3013   .next_nodes = {
3014 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3015     foreach_sr_policy_rewrite_next
3016 #undef _
3017   },
3018 };
3019 /* *INDENT-ON* */
3020
3021 /**
3022  * @brief Function BSID encapsulation
3023  */
3024 static_always_inline void
3025 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3026                                 vlib_buffer_t * b0,
3027                                 ip6_header_t * ip0,
3028                                 ip6_sr_header_t * sr0, u32 * next0)
3029 {
3030   ip6_address_t *new_dst0;
3031
3032   if (PREDICT_FALSE (!sr0))
3033     goto error_bsid_encaps;
3034
3035   if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3036     {
3037       if (PREDICT_TRUE (sr0->segments_left != 0))
3038         {
3039           sr0->segments_left -= 1;
3040           new_dst0 = (ip6_address_t *) (sr0->segments);
3041           new_dst0 += sr0->segments_left;
3042           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3043           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3044           return;
3045         }
3046     }
3047
3048 error_bsid_encaps:
3049   *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3050   b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3051 }
3052
3053 /**
3054  * @brief Graph node for applying a SR policy BSID - Encapsulation
3055  */
3056 static uword
3057 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3058                             vlib_frame_t * from_frame)
3059 {
3060   ip6_sr_main_t *sm = &sr_main;
3061   u32 n_left_from, next_index, *from, *to_next;
3062
3063   from = vlib_frame_vector_args (from_frame);
3064   n_left_from = from_frame->n_vectors;
3065
3066   next_index = node->cached_next_index;
3067
3068   int encap_pkts = 0, bsid_pkts = 0;
3069
3070   while (n_left_from > 0)
3071     {
3072       u32 n_left_to_next;
3073
3074       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3075
3076       /* Quad - Loop */
3077       while (n_left_from >= 8 && n_left_to_next >= 4)
3078         {
3079           u32 bi0, bi1, bi2, bi3;
3080           vlib_buffer_t *b0, *b1, *b2, *b3;
3081           u32 next0, next1, next2, next3;
3082           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3083           ip6_header_t *ip0, *ip1, *ip2, *ip3;
3084           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3085           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3086           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3087
3088           /* Prefetch next iteration. */
3089           {
3090             vlib_buffer_t *p4, *p5, *p6, *p7;
3091
3092             p4 = vlib_get_buffer (vm, from[4]);
3093             p5 = vlib_get_buffer (vm, from[5]);
3094             p6 = vlib_get_buffer (vm, from[6]);
3095             p7 = vlib_get_buffer (vm, from[7]);
3096
3097             /* Prefetch the buffer header and packet for the N+2 loop iteration */
3098             vlib_prefetch_buffer_header (p4, LOAD);
3099             vlib_prefetch_buffer_header (p5, LOAD);
3100             vlib_prefetch_buffer_header (p6, LOAD);
3101             vlib_prefetch_buffer_header (p7, LOAD);
3102
3103             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3104             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3105             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3106             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3107           }
3108
3109           to_next[0] = bi0 = from[0];
3110           to_next[1] = bi1 = from[1];
3111           to_next[2] = bi2 = from[2];
3112           to_next[3] = bi3 = from[3];
3113           from += 4;
3114           to_next += 4;
3115           n_left_from -= 4;
3116           n_left_to_next -= 4;
3117
3118           b0 = vlib_get_buffer (vm, bi0);
3119           b1 = vlib_get_buffer (vm, bi1);
3120           b2 = vlib_get_buffer (vm, bi2);
3121           b3 = vlib_get_buffer (vm, bi3);
3122
3123           sl0 =
3124             pool_elt_at_index (sm->sid_lists,
3125                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3126           sl1 =
3127             pool_elt_at_index (sm->sid_lists,
3128                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3129           sl2 =
3130             pool_elt_at_index (sm->sid_lists,
3131                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3132           sl3 =
3133             pool_elt_at_index (sm->sid_lists,
3134                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3135           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3136                   vec_len (sl0->rewrite));
3137           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3138                   vec_len (sl1->rewrite));
3139           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3140                   vec_len (sl2->rewrite));
3141           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3142                   vec_len (sl3->rewrite));
3143
3144           ip0_encap = vlib_buffer_get_current (b0);
3145           ip1_encap = vlib_buffer_get_current (b1);
3146           ip2_encap = vlib_buffer_get_current (b2);
3147           ip3_encap = vlib_buffer_get_current (b3);
3148
3149           sr0 =
3150             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3151                                  NULL);
3152           sr1 =
3153             ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3154                                  NULL);
3155           sr2 =
3156             ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3157                                  NULL);
3158           sr3 =
3159             ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3160                                  NULL);
3161
3162           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3163           end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3164           end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3165           end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3166
3167           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3168                             sl0->rewrite, vec_len (sl0->rewrite));
3169           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3170                             sl1->rewrite, vec_len (sl1->rewrite));
3171           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3172                             sl2->rewrite, vec_len (sl2->rewrite));
3173           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3174                             sl3->rewrite, vec_len (sl3->rewrite));
3175
3176           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3177           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3178           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3179           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3180
3181           ip0 = vlib_buffer_get_current (b0);
3182           ip1 = vlib_buffer_get_current (b1);
3183           ip2 = vlib_buffer_get_current (b2);
3184           ip3 = vlib_buffer_get_current (b3);
3185
3186           encaps_processing_v6 (node, b0, ip0, ip0_encap);
3187           encaps_processing_v6 (node, b1, ip1, ip1_encap);
3188           encaps_processing_v6 (node, b2, ip2, ip2_encap);
3189           encaps_processing_v6 (node, b3, ip3, ip3_encap);
3190
3191           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3192             {
3193               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3194                 {
3195                   sr_policy_rewrite_trace_t *tr =
3196                     vlib_add_trace (vm, node, b0, sizeof (*tr));
3197                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3198                                     sizeof (tr->src.as_u8));
3199                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3200                                     sizeof (tr->dst.as_u8));
3201                 }
3202
3203               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3204                 {
3205                   sr_policy_rewrite_trace_t *tr =
3206                     vlib_add_trace (vm, node, b1, sizeof (*tr));
3207                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3208                                     sizeof (tr->src.as_u8));
3209                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3210                                     sizeof (tr->dst.as_u8));
3211                 }
3212
3213               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3214                 {
3215                   sr_policy_rewrite_trace_t *tr =
3216                     vlib_add_trace (vm, node, b2, sizeof (*tr));
3217                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3218                                     sizeof (tr->src.as_u8));
3219                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3220                                     sizeof (tr->dst.as_u8));
3221                 }
3222
3223               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3224                 {
3225                   sr_policy_rewrite_trace_t *tr =
3226                     vlib_add_trace (vm, node, b3, sizeof (*tr));
3227                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3228                                     sizeof (tr->src.as_u8));
3229                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3230                                     sizeof (tr->dst.as_u8));
3231                 }
3232             }
3233
3234           encap_pkts += 4;
3235           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3236                                            n_left_to_next, bi0, bi1, bi2, bi3,
3237                                            next0, next1, next2, next3);
3238         }
3239
3240       /* Single loop for potentially the last three packets */
3241       while (n_left_from > 0 && n_left_to_next > 0)
3242         {
3243           u32 bi0;
3244           vlib_buffer_t *b0;
3245           ip6_header_t *ip0 = 0, *ip0_encap = 0;
3246           ip6_sr_header_t *sr0;
3247           ip6_sr_sl_t *sl0;
3248           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3249
3250           bi0 = from[0];
3251           to_next[0] = bi0;
3252           from += 1;
3253           to_next += 1;
3254           n_left_from -= 1;
3255           n_left_to_next -= 1;
3256           b0 = vlib_get_buffer (vm, bi0);
3257
3258           sl0 =
3259             pool_elt_at_index (sm->sid_lists,
3260                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3261           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3262                   vec_len (sl0->rewrite));
3263
3264           ip0_encap = vlib_buffer_get_current (b0);
3265           sr0 =
3266             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3267                                  NULL);
3268           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3269
3270           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3271                             sl0->rewrite, vec_len (sl0->rewrite));
3272           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3273
3274           ip0 = vlib_buffer_get_current (b0);
3275
3276           encaps_processing_v6 (node, b0, ip0, ip0_encap);
3277
3278           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3279               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3280             {
3281               sr_policy_rewrite_trace_t *tr =
3282                 vlib_add_trace (vm, node, b0, sizeof (*tr));
3283               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3284                                 sizeof (tr->src.as_u8));
3285               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3286                                 sizeof (tr->dst.as_u8));
3287             }
3288
3289           encap_pkts++;
3290           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3291                                            n_left_to_next, bi0, next0);
3292         }
3293
3294       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3295     }
3296
3297   /* Update counters */
3298   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3299                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3300                                encap_pkts);
3301   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3302                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3303                                bsid_pkts);
3304
3305   return from_frame->n_vectors;
3306 }
3307
3308 /* *INDENT-OFF* */
3309 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3310   .function = sr_policy_rewrite_b_encaps,
3311   .name = "sr-pl-rewrite-b-encaps",
3312   .vector_size = sizeof (u32),
3313   .format_trace = format_sr_policy_rewrite_trace,
3314   .type = VLIB_NODE_TYPE_INTERNAL,
3315   .n_errors = SR_POLICY_REWRITE_N_ERROR,
3316   .error_strings = sr_policy_rewrite_error_strings,
3317   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3318   .next_nodes = {
3319 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3320     foreach_sr_policy_rewrite_next
3321 #undef _
3322   },
3323 };
3324 /* *INDENT-ON* */
3325
3326 /*************************** SR Policy plugins ******************************/
3327 /**
3328  * @brief SR Policy plugin registry
3329  */
3330 int
3331 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3332                              u8 * keyword_str, u8 * def_str,
3333                              u8 * params_str, u8 prefix_length,
3334                              dpo_type_t * dpo,
3335                              format_function_t * ls_format,
3336                              unformat_function_t * ls_unformat,
3337                              sr_p_plugin_callback_t * creation_fn,
3338                              sr_p_plugin_callback_t * removal_fn)
3339 {
3340   ip6_sr_main_t *sm = &sr_main;
3341   uword *p;
3342
3343   sr_policy_fn_registration_t *plugin;
3344
3345   /* Did this function exist? If so update it */
3346   p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3347   if (p)
3348     {
3349       plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3350     }
3351   /* Else create a new one and set hash key */
3352   else
3353     {
3354       pool_get (sm->policy_plugin_functions, plugin);
3355       hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3356                     plugin - sm->policy_plugin_functions);
3357     }
3358
3359   clib_memset (plugin, 0, sizeof (*plugin));
3360
3361   plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3362   plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3363   plugin->prefix_length = prefix_length;
3364   plugin->ls_format = ls_format;
3365   plugin->ls_unformat = ls_unformat;
3366   plugin->creation = creation_fn;
3367   plugin->removal = removal_fn;
3368   clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3369   plugin->function_name = format (0, "%s%c", fn_name, 0);
3370   plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3371   plugin->def_str = format (0, "%s%c", def_str, 0);
3372   plugin->params_str = format (0, "%s%c", params_str, 0);
3373
3374   return plugin->sr_policy_function_number;
3375 }
3376
3377 /**
3378  * @brief CLI function to 'show' all available SR LocalSID behaviors
3379  */
3380 static clib_error_t *
3381 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3382                                      unformat_input_t * input,
3383                                      vlib_cli_command_t * cmd)
3384 {
3385   ip6_sr_main_t *sm = &sr_main;
3386   sr_policy_fn_registration_t *plugin;
3387   sr_policy_fn_registration_t **plugins_vec = 0;
3388   int i;
3389
3390   vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3391
3392   /* *INDENT-OFF* */
3393   pool_foreach (plugin, sm->policy_plugin_functions,
3394     ({ vec_add1 (plugins_vec, plugin); }));
3395   /* *INDENT-ON* */
3396
3397   vlib_cli_output (vm, "Plugin behaviors:\n");
3398   for (i = 0; i < vec_len (plugins_vec); i++)
3399     {
3400       plugin = plugins_vec[i];
3401       vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3402                        plugin->def_str);
3403       vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3404     }
3405   return 0;
3406 }
3407
3408 /* *INDENT-OFF* */
3409 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3410   .path = "show sr policy behaviors",
3411   .short_help = "show sr policy behaviors",
3412   .function = show_sr_policy_behaviors_command_fn,
3413 };
3414 /* *INDENT-ON* */
3415
3416 /*************************** SR Segment Lists DPOs ****************************/
3417 static u8 *
3418 format_sr_segment_list_dpo (u8 * s, va_list * args)
3419 {
3420   ip6_sr_main_t *sm = &sr_main;
3421   ip6_address_t *addr;
3422   ip6_sr_sl_t *sl;
3423
3424   index_t index = va_arg (*args, index_t);
3425   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3426   s = format (s, "SR: Segment List index:[%d]", index);
3427   s = format (s, "\n\tSegments:");
3428
3429   sl = pool_elt_at_index (sm->sid_lists, index);
3430
3431   s = format (s, "< ");
3432   vec_foreach (addr, sl->segments)
3433   {
3434     s = format (s, "%U, ", format_ip6_address, addr);
3435   }
3436   s = format (s, "\b\b > - ");
3437   s = format (s, "Weight: %u", sl->weight);
3438
3439   return s;
3440 }
3441
3442 const static dpo_vft_t sr_policy_rewrite_vft = {
3443   .dv_lock = sr_dpo_lock,
3444   .dv_unlock = sr_dpo_unlock,
3445   .dv_format = format_sr_segment_list_dpo,
3446 };
3447
3448 const static char *const sr_pr_encaps_ip6_nodes[] = {
3449   "sr-pl-rewrite-encaps",
3450   NULL,
3451 };
3452
3453 const static char *const sr_pr_encaps_ip4_nodes[] = {
3454   "sr-pl-rewrite-encaps-v4",
3455   NULL,
3456 };
3457
3458 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3459   [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3460   [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3461 };
3462
3463 const static char *const sr_pr_insert_ip6_nodes[] = {
3464   "sr-pl-rewrite-insert",
3465   NULL,
3466 };
3467
3468 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3469   [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3470 };
3471
3472 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3473   "sr-pl-rewrite-b-insert",
3474   NULL,
3475 };
3476
3477 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3478   [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3479 };
3480
3481 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3482   "sr-pl-rewrite-b-encaps",
3483   NULL,
3484 };
3485
3486 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3487   [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3488 };
3489
3490 /********************* SR Policy Rewrite initialization ***********************/
3491 /**
3492  * @brief SR Policy Rewrite initialization
3493  */
3494 clib_error_t *
3495 sr_policy_rewrite_init (vlib_main_t * vm)
3496 {
3497   ip6_sr_main_t *sm = &sr_main;
3498
3499   /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3500   mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3501               sizeof (ip6_address_t));
3502
3503   /* Init SR VPO DPOs type */
3504   sr_pr_encaps_dpo_type =
3505     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3506
3507   sr_pr_insert_dpo_type =
3508     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3509
3510   sr_pr_bsid_encaps_dpo_type =
3511     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3512
3513   sr_pr_bsid_insert_dpo_type =
3514     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3515
3516   /* Register the L2 encaps node used in HW redirect */
3517   sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3518
3519   sm->fib_table_ip6 = (u32) ~ 0;
3520   sm->fib_table_ip4 = (u32) ~ 0;
3521
3522   return 0;
3523 }
3524
3525 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3526
3527
3528 /*
3529 * fd.io coding-style-patch-verification: ON
3530 *
3531 * Local Variables:
3532 * eval: (c-set-style "gnu")
3533 * End:
3534 */