sr: SRv6 FlowLabel Added
[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 /**
1193  * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1194  */
1195 static clib_error_t *
1196 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1197                                      unformat_input_t * input,
1198                                      vlib_cli_command_t * cmd)
1199 {
1200   vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1201
1202   return 0;
1203 }
1204
1205 /* *INDENT-OFF* */
1206 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1207   .path = "show sr encaps hop-limit",
1208   .short_help = "show sr encaps hop-limit",
1209   .function = show_sr_encaps_hop_limit_command_fn,
1210 };
1211 /* *INDENT-ON* */
1212
1213 /*************************** SR rewrite graph node ****************************/
1214 /**
1215  * @brief Trace for the SR Policy Rewrite graph node
1216  */
1217 static u8 *
1218 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1219 {
1220   //TODO
1221   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1222   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1223   sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1224
1225   s = format
1226     (s, "SR-policy-rewrite: src %U dst %U",
1227      format_ip6_address, &t->src, format_ip6_address, &t->dst);
1228
1229   return s;
1230 }
1231
1232 /**
1233  * @brief IPv6 encapsulation processing as per RFC2473
1234  */
1235 static_always_inline void
1236 encaps_processing_v6 (vlib_node_runtime_t * node,
1237                       vlib_buffer_t * b0,
1238                       ip6_header_t * ip0, ip6_header_t * ip0_encap)
1239 {
1240   u32 new_l0;
1241   u32 flow_label;
1242
1243   ip0_encap->hop_limit -= 1;
1244   new_l0 =
1245     ip0->payload_length + sizeof (ip6_header_t) +
1246     clib_net_to_host_u16 (ip0_encap->payload_length);
1247   ip0->payload_length = clib_host_to_net_u16 (new_l0);
1248
1249   flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1250   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1251     0 |
1252     (clib_net_to_host_u32 (
1253        ip0_encap->ip_version_traffic_class_and_flow_label) &
1254      0xfff00000) |
1255     (flow_label & 0x0000ffff));
1256 }
1257
1258 /**
1259  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1260  */
1261 static uword
1262 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1263                           vlib_frame_t * from_frame)
1264 {
1265   ip6_sr_main_t *sm = &sr_main;
1266   u32 n_left_from, next_index, *from, *to_next;
1267
1268   from = vlib_frame_vector_args (from_frame);
1269   n_left_from = from_frame->n_vectors;
1270
1271   next_index = node->cached_next_index;
1272
1273   int encap_pkts = 0, bsid_pkts = 0;
1274
1275   while (n_left_from > 0)
1276     {
1277       u32 n_left_to_next;
1278
1279       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1280
1281       /* Quad - Loop */
1282       while (n_left_from >= 8 && n_left_to_next >= 4)
1283         {
1284           u32 bi0, bi1, bi2, bi3;
1285           vlib_buffer_t *b0, *b1, *b2, *b3;
1286           u32 next0, next1, next2, next3;
1287           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1288           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1289           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1290           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1291
1292           /* Prefetch next iteration. */
1293           {
1294             vlib_buffer_t *p4, *p5, *p6, *p7;
1295
1296             p4 = vlib_get_buffer (vm, from[4]);
1297             p5 = vlib_get_buffer (vm, from[5]);
1298             p6 = vlib_get_buffer (vm, from[6]);
1299             p7 = vlib_get_buffer (vm, from[7]);
1300
1301             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1302             vlib_prefetch_buffer_header (p4, LOAD);
1303             vlib_prefetch_buffer_header (p5, LOAD);
1304             vlib_prefetch_buffer_header (p6, LOAD);
1305             vlib_prefetch_buffer_header (p7, LOAD);
1306
1307             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1308             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1309             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1310             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1311           }
1312
1313           to_next[0] = bi0 = from[0];
1314           to_next[1] = bi1 = from[1];
1315           to_next[2] = bi2 = from[2];
1316           to_next[3] = bi3 = from[3];
1317           from += 4;
1318           to_next += 4;
1319           n_left_from -= 4;
1320           n_left_to_next -= 4;
1321
1322           b0 = vlib_get_buffer (vm, bi0);
1323           b1 = vlib_get_buffer (vm, bi1);
1324           b2 = vlib_get_buffer (vm, bi2);
1325           b3 = vlib_get_buffer (vm, bi3);
1326
1327           sl0 =
1328             pool_elt_at_index (sm->sid_lists,
1329                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1330           sl1 =
1331             pool_elt_at_index (sm->sid_lists,
1332                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1333           sl2 =
1334             pool_elt_at_index (sm->sid_lists,
1335                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1336           sl3 =
1337             pool_elt_at_index (sm->sid_lists,
1338                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1339
1340           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1341                   vec_len (sl0->rewrite));
1342           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1343                   vec_len (sl1->rewrite));
1344           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1345                   vec_len (sl2->rewrite));
1346           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1347                   vec_len (sl3->rewrite));
1348
1349           ip0_encap = vlib_buffer_get_current (b0);
1350           ip1_encap = vlib_buffer_get_current (b1);
1351           ip2_encap = vlib_buffer_get_current (b2);
1352           ip3_encap = vlib_buffer_get_current (b3);
1353
1354           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1355                             sl0->rewrite, vec_len (sl0->rewrite));
1356           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1357                             sl1->rewrite, vec_len (sl1->rewrite));
1358           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1359                             sl2->rewrite, vec_len (sl2->rewrite));
1360           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1361                             sl3->rewrite, vec_len (sl3->rewrite));
1362
1363           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1364           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1365           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1366           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1367
1368           ip0 = vlib_buffer_get_current (b0);
1369           ip1 = vlib_buffer_get_current (b1);
1370           ip2 = vlib_buffer_get_current (b2);
1371           ip3 = vlib_buffer_get_current (b3);
1372
1373           encaps_processing_v6 (node, b0, ip0, ip0_encap);
1374           encaps_processing_v6 (node, b1, ip1, ip1_encap);
1375           encaps_processing_v6 (node, b2, ip2, ip2_encap);
1376           encaps_processing_v6 (node, b3, ip3, ip3_encap);
1377
1378           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1379             {
1380               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1381                 {
1382                   sr_policy_rewrite_trace_t *tr =
1383                     vlib_add_trace (vm, node, b0, sizeof (*tr));
1384                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1385                                     sizeof (tr->src.as_u8));
1386                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1387                                     sizeof (tr->dst.as_u8));
1388                 }
1389
1390               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1391                 {
1392                   sr_policy_rewrite_trace_t *tr =
1393                     vlib_add_trace (vm, node, b1, sizeof (*tr));
1394                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1395                                     sizeof (tr->src.as_u8));
1396                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1397                                     sizeof (tr->dst.as_u8));
1398                 }
1399
1400               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1401                 {
1402                   sr_policy_rewrite_trace_t *tr =
1403                     vlib_add_trace (vm, node, b2, sizeof (*tr));
1404                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1405                                     sizeof (tr->src.as_u8));
1406                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1407                                     sizeof (tr->dst.as_u8));
1408                 }
1409
1410               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1411                 {
1412                   sr_policy_rewrite_trace_t *tr =
1413                     vlib_add_trace (vm, node, b3, sizeof (*tr));
1414                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1415                                     sizeof (tr->src.as_u8));
1416                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1417                                     sizeof (tr->dst.as_u8));
1418                 }
1419             }
1420
1421           encap_pkts += 4;
1422           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1423                                            n_left_to_next, bi0, bi1, bi2, bi3,
1424                                            next0, next1, next2, next3);
1425         }
1426
1427       /* Single loop for potentially the last three packets */
1428       while (n_left_from > 0 && n_left_to_next > 0)
1429         {
1430           u32 bi0;
1431           vlib_buffer_t *b0;
1432           ip6_header_t *ip0 = 0, *ip0_encap = 0;
1433           ip6_sr_sl_t *sl0;
1434           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1435
1436           bi0 = from[0];
1437           to_next[0] = bi0;
1438           from += 1;
1439           to_next += 1;
1440           n_left_from -= 1;
1441           n_left_to_next -= 1;
1442           b0 = vlib_get_buffer (vm, bi0);
1443
1444           sl0 =
1445             pool_elt_at_index (sm->sid_lists,
1446                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1447           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1448                   vec_len (sl0->rewrite));
1449
1450           ip0_encap = vlib_buffer_get_current (b0);
1451
1452           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1453                             sl0->rewrite, vec_len (sl0->rewrite));
1454           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1455
1456           ip0 = vlib_buffer_get_current (b0);
1457
1458           encaps_processing_v6 (node, b0, ip0, ip0_encap);
1459
1460           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1461               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1462             {
1463               sr_policy_rewrite_trace_t *tr =
1464                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1465               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1466                                 sizeof (tr->src.as_u8));
1467               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1468                                 sizeof (tr->dst.as_u8));
1469             }
1470
1471           encap_pkts++;
1472           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1473                                            n_left_to_next, bi0, next0);
1474         }
1475
1476       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1477     }
1478
1479   /* Update counters */
1480   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1481                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1482                                encap_pkts);
1483   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1484                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1485                                bsid_pkts);
1486
1487   return from_frame->n_vectors;
1488 }
1489
1490 /* *INDENT-OFF* */
1491 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1492   .function = sr_policy_rewrite_encaps,
1493   .name = "sr-pl-rewrite-encaps",
1494   .vector_size = sizeof (u32),
1495   .format_trace = format_sr_policy_rewrite_trace,
1496   .type = VLIB_NODE_TYPE_INTERNAL,
1497   .n_errors = SR_POLICY_REWRITE_N_ERROR,
1498   .error_strings = sr_policy_rewrite_error_strings,
1499   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1500   .next_nodes = {
1501 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1502     foreach_sr_policy_rewrite_next
1503 #undef _
1504   },
1505 };
1506 /* *INDENT-ON* */
1507
1508 /**
1509  * @brief IPv4 encapsulation processing as per RFC2473
1510  */
1511 static_always_inline void
1512 encaps_processing_v4 (vlib_node_runtime_t * node,
1513                       vlib_buffer_t * b0,
1514                       ip6_header_t * ip0, ip4_header_t * ip0_encap)
1515 {
1516   u32 new_l0;
1517   ip6_sr_header_t *sr0;
1518
1519   u32 checksum0;
1520   u32 flow_label;
1521
1522   /* Inner IPv4: Decrement TTL & update checksum */
1523   ip0_encap->ttl -= 1;
1524   checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1525   checksum0 += checksum0 >= 0xffff;
1526   ip0_encap->checksum = checksum0;
1527
1528   /* Outer IPv6: Update length, FL, proto */
1529   new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1530   ip0->payload_length = clib_host_to_net_u16 (new_l0);
1531   flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1532   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1533     0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1534     (flow_label & 0x0000ffff));
1535   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1536     {
1537       sr0 = (void *) (ip0 + 1);
1538       sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1539     }
1540   else
1541     ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1542 }
1543
1544 /**
1545  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1546  */
1547 static uword
1548 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1549                              vlib_frame_t * from_frame)
1550 {
1551   ip6_sr_main_t *sm = &sr_main;
1552   u32 n_left_from, next_index, *from, *to_next;
1553
1554   from = vlib_frame_vector_args (from_frame);
1555   n_left_from = from_frame->n_vectors;
1556
1557   next_index = node->cached_next_index;
1558
1559   int encap_pkts = 0, bsid_pkts = 0;
1560
1561   while (n_left_from > 0)
1562     {
1563       u32 n_left_to_next;
1564
1565       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1566
1567       /* Quad - Loop */
1568       while (n_left_from >= 8 && n_left_to_next >= 4)
1569         {
1570           u32 bi0, bi1, bi2, bi3;
1571           vlib_buffer_t *b0, *b1, *b2, *b3;
1572           u32 next0, next1, next2, next3;
1573           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1574           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1575           ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1576           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1577
1578           /* Prefetch next iteration. */
1579           {
1580             vlib_buffer_t *p4, *p5, *p6, *p7;
1581
1582             p4 = vlib_get_buffer (vm, from[4]);
1583             p5 = vlib_get_buffer (vm, from[5]);
1584             p6 = vlib_get_buffer (vm, from[6]);
1585             p7 = vlib_get_buffer (vm, from[7]);
1586
1587             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1588             vlib_prefetch_buffer_header (p4, LOAD);
1589             vlib_prefetch_buffer_header (p5, LOAD);
1590             vlib_prefetch_buffer_header (p6, LOAD);
1591             vlib_prefetch_buffer_header (p7, LOAD);
1592
1593             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1594             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1595             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1596             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1597           }
1598
1599           to_next[0] = bi0 = from[0];
1600           to_next[1] = bi1 = from[1];
1601           to_next[2] = bi2 = from[2];
1602           to_next[3] = bi3 = from[3];
1603           from += 4;
1604           to_next += 4;
1605           n_left_from -= 4;
1606           n_left_to_next -= 4;
1607
1608           b0 = vlib_get_buffer (vm, bi0);
1609           b1 = vlib_get_buffer (vm, bi1);
1610           b2 = vlib_get_buffer (vm, bi2);
1611           b3 = vlib_get_buffer (vm, bi3);
1612
1613           sl0 =
1614             pool_elt_at_index (sm->sid_lists,
1615                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1616           sl1 =
1617             pool_elt_at_index (sm->sid_lists,
1618                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1619           sl2 =
1620             pool_elt_at_index (sm->sid_lists,
1621                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1622           sl3 =
1623             pool_elt_at_index (sm->sid_lists,
1624                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1625           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1626                   vec_len (sl0->rewrite));
1627           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1628                   vec_len (sl1->rewrite));
1629           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1630                   vec_len (sl2->rewrite));
1631           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1632                   vec_len (sl3->rewrite));
1633
1634           ip0_encap = vlib_buffer_get_current (b0);
1635           ip1_encap = vlib_buffer_get_current (b1);
1636           ip2_encap = vlib_buffer_get_current (b2);
1637           ip3_encap = vlib_buffer_get_current (b3);
1638
1639           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1640                             sl0->rewrite, vec_len (sl0->rewrite));
1641           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1642                             sl1->rewrite, vec_len (sl1->rewrite));
1643           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1644                             sl2->rewrite, vec_len (sl2->rewrite));
1645           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1646                             sl3->rewrite, vec_len (sl3->rewrite));
1647
1648           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1649           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1650           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1651           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1652
1653           ip0 = vlib_buffer_get_current (b0);
1654           ip1 = vlib_buffer_get_current (b1);
1655           ip2 = vlib_buffer_get_current (b2);
1656           ip3 = vlib_buffer_get_current (b3);
1657
1658           encaps_processing_v4 (node, b0, ip0, ip0_encap);
1659           encaps_processing_v4 (node, b1, ip1, ip1_encap);
1660           encaps_processing_v4 (node, b2, ip2, ip2_encap);
1661           encaps_processing_v4 (node, b3, ip3, ip3_encap);
1662
1663           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1664             {
1665               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1666                 {
1667                   sr_policy_rewrite_trace_t *tr =
1668                     vlib_add_trace (vm, node, b0, sizeof (*tr));
1669                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1670                                     sizeof (tr->src.as_u8));
1671                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1672                                     sizeof (tr->dst.as_u8));
1673                 }
1674
1675               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1676                 {
1677                   sr_policy_rewrite_trace_t *tr =
1678                     vlib_add_trace (vm, node, b1, sizeof (*tr));
1679                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1680                                     sizeof (tr->src.as_u8));
1681                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1682                                     sizeof (tr->dst.as_u8));
1683                 }
1684
1685               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1686                 {
1687                   sr_policy_rewrite_trace_t *tr =
1688                     vlib_add_trace (vm, node, b2, sizeof (*tr));
1689                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1690                                     sizeof (tr->src.as_u8));
1691                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1692                                     sizeof (tr->dst.as_u8));
1693                 }
1694
1695               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1696                 {
1697                   sr_policy_rewrite_trace_t *tr =
1698                     vlib_add_trace (vm, node, b3, sizeof (*tr));
1699                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1700                                     sizeof (tr->src.as_u8));
1701                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1702                                     sizeof (tr->dst.as_u8));
1703                 }
1704             }
1705
1706           encap_pkts += 4;
1707           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1708                                            n_left_to_next, bi0, bi1, bi2, bi3,
1709                                            next0, next1, next2, next3);
1710         }
1711
1712       /* Single loop for potentially the last three packets */
1713       while (n_left_from > 0 && n_left_to_next > 0)
1714         {
1715           u32 bi0;
1716           vlib_buffer_t *b0;
1717           ip6_header_t *ip0 = 0;
1718           ip4_header_t *ip0_encap = 0;
1719           ip6_sr_sl_t *sl0;
1720           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1721
1722           bi0 = from[0];
1723           to_next[0] = bi0;
1724           from += 1;
1725           to_next += 1;
1726           n_left_from -= 1;
1727           n_left_to_next -= 1;
1728           b0 = vlib_get_buffer (vm, bi0);
1729
1730           sl0 =
1731             pool_elt_at_index (sm->sid_lists,
1732                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1733           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1734                   vec_len (sl0->rewrite));
1735
1736           ip0_encap = vlib_buffer_get_current (b0);
1737
1738           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1739                             sl0->rewrite, vec_len (sl0->rewrite));
1740           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1741
1742           ip0 = vlib_buffer_get_current (b0);
1743
1744           encaps_processing_v4 (node, b0, ip0, ip0_encap);
1745
1746           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1747               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1748             {
1749               sr_policy_rewrite_trace_t *tr =
1750                 vlib_add_trace (vm, node, b0, sizeof (*tr));
1751               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1752                                 sizeof (tr->src.as_u8));
1753               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1754                                 sizeof (tr->dst.as_u8));
1755             }
1756
1757           encap_pkts++;
1758           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1759                                            n_left_to_next, bi0, next0);
1760         }
1761
1762       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1763     }
1764
1765   /* Update counters */
1766   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1767                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1768                                encap_pkts);
1769   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1770                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1771                                bsid_pkts);
1772
1773   return from_frame->n_vectors;
1774 }
1775
1776 /* *INDENT-OFF* */
1777 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1778   .function = sr_policy_rewrite_encaps_v4,
1779   .name = "sr-pl-rewrite-encaps-v4",
1780   .vector_size = sizeof (u32),
1781   .format_trace = format_sr_policy_rewrite_trace,
1782   .type = VLIB_NODE_TYPE_INTERNAL,
1783   .n_errors = SR_POLICY_REWRITE_N_ERROR,
1784   .error_strings = sr_policy_rewrite_error_strings,
1785   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1786   .next_nodes = {
1787 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1788     foreach_sr_policy_rewrite_next
1789 #undef _
1790   },
1791 };
1792 /* *INDENT-ON* */
1793
1794 always_inline u32
1795 ip_flow_hash (void *data)
1796 {
1797   ip4_header_t *iph = (ip4_header_t *) data;
1798
1799   if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1800     return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1801   else
1802     return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1803 }
1804
1805 always_inline u64
1806 mac_to_u64 (u8 * m)
1807 {
1808   return (*((u64 *) m) & 0xffffffffffff);
1809 }
1810
1811 always_inline u32
1812 l2_flow_hash (vlib_buffer_t * b0)
1813 {
1814   ethernet_header_t *eh;
1815   u64 a, b, c;
1816   uword is_ip, eh_size;
1817   u16 eh_type;
1818
1819   eh = vlib_buffer_get_current (b0);
1820   eh_type = clib_net_to_host_u16 (eh->type);
1821   eh_size = ethernet_buffer_header_size (b0);
1822
1823   is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1824
1825   /* since we have 2 cache lines, use them */
1826   if (is_ip)
1827     a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1828   else
1829     a = eh->type;
1830
1831   b = mac_to_u64 ((u8 *) eh->dst_address);
1832   c = mac_to_u64 ((u8 *) eh->src_address);
1833   hash_mix64 (a, b, c);
1834
1835   return (u32) c;
1836 }
1837
1838 /**
1839  * @brief Graph node for applying a SR policy into a L2 frame
1840  */
1841 static uword
1842 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1843                              vlib_frame_t * from_frame)
1844 {
1845   ip6_sr_main_t *sm = &sr_main;
1846   u32 n_left_from, next_index, *from, *to_next;
1847
1848   from = vlib_frame_vector_args (from_frame);
1849   n_left_from = from_frame->n_vectors;
1850
1851   next_index = node->cached_next_index;
1852
1853   int encap_pkts = 0, bsid_pkts = 0;
1854
1855   while (n_left_from > 0)
1856     {
1857       u32 n_left_to_next;
1858
1859       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1860
1861       /* Quad - Loop */
1862       while (n_left_from >= 8 && n_left_to_next >= 4)
1863         {
1864           u32 bi0, bi1, bi2, bi3;
1865           vlib_buffer_t *b0, *b1, *b2, *b3;
1866           u32 next0, next1, next2, next3;
1867           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1868           ethernet_header_t *en0, *en1, *en2, *en3;
1869           ip6_header_t *ip0, *ip1, *ip2, *ip3;
1870           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1871           ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1872           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1873           u32 flow_label0, flow_label1, flow_label2, flow_label3;
1874
1875           /* Prefetch next iteration. */
1876           {
1877             vlib_buffer_t *p4, *p5, *p6, *p7;
1878
1879             p4 = vlib_get_buffer (vm, from[4]);
1880             p5 = vlib_get_buffer (vm, from[5]);
1881             p6 = vlib_get_buffer (vm, from[6]);
1882             p7 = vlib_get_buffer (vm, from[7]);
1883
1884             /* Prefetch the buffer header and packet for the N+2 loop iteration */
1885             vlib_prefetch_buffer_header (p4, LOAD);
1886             vlib_prefetch_buffer_header (p5, LOAD);
1887             vlib_prefetch_buffer_header (p6, LOAD);
1888             vlib_prefetch_buffer_header (p7, LOAD);
1889
1890             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1891             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1892             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1893             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1894           }
1895
1896           to_next[0] = bi0 = from[0];
1897           to_next[1] = bi1 = from[1];
1898           to_next[2] = bi2 = from[2];
1899           to_next[3] = bi3 = from[3];
1900           from += 4;
1901           to_next += 4;
1902           n_left_from -= 4;
1903           n_left_to_next -= 4;
1904
1905           b0 = vlib_get_buffer (vm, bi0);
1906           b1 = vlib_get_buffer (vm, bi1);
1907           b2 = vlib_get_buffer (vm, bi2);
1908           b3 = vlib_get_buffer (vm, bi3);
1909
1910           sp0 = pool_elt_at_index (sm->sr_policies,
1911                                    sm->sw_iface_sr_policies[vnet_buffer
1912                                                             (b0)->sw_if_index
1913                                                             [VLIB_RX]]);
1914
1915           sp1 = pool_elt_at_index (sm->sr_policies,
1916                                    sm->sw_iface_sr_policies[vnet_buffer
1917                                                             (b1)->sw_if_index
1918                                                             [VLIB_RX]]);
1919
1920           sp2 = pool_elt_at_index (sm->sr_policies,
1921                                    sm->sw_iface_sr_policies[vnet_buffer
1922                                                             (b2)->sw_if_index
1923                                                             [VLIB_RX]]);
1924
1925           sp3 = pool_elt_at_index (sm->sr_policies,
1926                                    sm->sw_iface_sr_policies[vnet_buffer
1927                                                             (b3)->sw_if_index
1928                                                             [VLIB_RX]]);
1929           flow_label0 = l2_flow_hash (b0);
1930           flow_label1 = l2_flow_hash (b1);
1931           flow_label2 = l2_flow_hash (b2);
1932           flow_label3 = l2_flow_hash (b3);
1933
1934           if (vec_len (sp0->segments_lists) == 1)
1935             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1936           else
1937             {
1938               vnet_buffer (b0)->ip.flow_hash = flow_label0;
1939               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1940                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1941                                      (vec_len (sp0->segments_lists) - 1))];
1942             }
1943
1944           if (vec_len (sp1->segments_lists) == 1)
1945             vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1946           else
1947             {
1948               vnet_buffer (b1)->ip.flow_hash = flow_label1;
1949               vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1950                 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1951                                      (vec_len (sp1->segments_lists) - 1))];
1952             }
1953
1954           if (vec_len (sp2->segments_lists) == 1)
1955             vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1956           else
1957             {
1958               vnet_buffer (b2)->ip.flow_hash = flow_label2;
1959               vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1960                 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1961                                      (vec_len (sp2->segments_lists) - 1))];
1962             }
1963
1964           if (vec_len (sp3->segments_lists) == 1)
1965             vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1966           else
1967             {
1968               vnet_buffer (b3)->ip.flow_hash = flow_label3;
1969               vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1970                 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1971                                      (vec_len (sp3->segments_lists) - 1))];
1972             }
1973
1974           sl0 =
1975             pool_elt_at_index (sm->sid_lists,
1976                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1977           sl1 =
1978             pool_elt_at_index (sm->sid_lists,
1979                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1980           sl2 =
1981             pool_elt_at_index (sm->sid_lists,
1982                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1983           sl3 =
1984             pool_elt_at_index (sm->sid_lists,
1985                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1986
1987           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1988                   vec_len (sl0->rewrite));
1989           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1990                   vec_len (sl1->rewrite));
1991           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1992                   vec_len (sl2->rewrite));
1993           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1994                   vec_len (sl3->rewrite));
1995
1996           en0 = vlib_buffer_get_current (b0);
1997           en1 = vlib_buffer_get_current (b1);
1998           en2 = vlib_buffer_get_current (b2);
1999           en3 = vlib_buffer_get_current (b3);
2000
2001           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2002                             sl0->rewrite, vec_len (sl0->rewrite));
2003           clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2004                             sl1->rewrite, vec_len (sl1->rewrite));
2005           clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2006                             sl2->rewrite, vec_len (sl2->rewrite));
2007           clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2008                             sl3->rewrite, vec_len (sl3->rewrite));
2009
2010           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2011           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2012           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2013           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2014
2015           ip0 = vlib_buffer_get_current (b0);
2016           ip1 = vlib_buffer_get_current (b1);
2017           ip2 = vlib_buffer_get_current (b2);
2018           ip3 = vlib_buffer_get_current (b3);
2019
2020           ip0->payload_length =
2021             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2022           ip1->payload_length =
2023             clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2024           ip2->payload_length =
2025             clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2026           ip3->payload_length =
2027             clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2028
2029           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2030             {
2031               sr0 = (void *) (ip0 + 1);
2032               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2033             }
2034           else
2035             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2036
2037           if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2038             {
2039               sr1 = (void *) (ip1 + 1);
2040               sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2041             }
2042           else
2043             ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2044
2045           if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2046             {
2047               sr2 = (void *) (ip2 + 1);
2048               sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2049             }
2050           else
2051             ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2052
2053           if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2054             {
2055               sr3 = (void *) (ip3 + 1);
2056               sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2057             }
2058           else
2059             ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2060
2061           /* TC is set to 0 for all ethernet frames, should be taken from COS
2062            * od DSCP of encapsulated packet in the future */
2063           ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2064             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2065           ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2066             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2067           ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2068             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2069           ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2070             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2071
2072           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2073             {
2074               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2075                 {
2076                   sr_policy_rewrite_trace_t *tr =
2077                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2078                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2079                                     sizeof (tr->src.as_u8));
2080                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2081                                     sizeof (tr->dst.as_u8));
2082                 }
2083
2084               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2085                 {
2086                   sr_policy_rewrite_trace_t *tr =
2087                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2088                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2089                                     sizeof (tr->src.as_u8));
2090                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2091                                     sizeof (tr->dst.as_u8));
2092                 }
2093
2094               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2095                 {
2096                   sr_policy_rewrite_trace_t *tr =
2097                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2098                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2099                                     sizeof (tr->src.as_u8));
2100                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2101                                     sizeof (tr->dst.as_u8));
2102                 }
2103
2104               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2105                 {
2106                   sr_policy_rewrite_trace_t *tr =
2107                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2108                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2109                                     sizeof (tr->src.as_u8));
2110                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2111                                     sizeof (tr->dst.as_u8));
2112                 }
2113             }
2114
2115           encap_pkts += 4;
2116           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2117                                            n_left_to_next, bi0, bi1, bi2, bi3,
2118                                            next0, next1, next2, next3);
2119         }
2120
2121       /* Single loop for potentially the last three packets */
2122       while (n_left_from > 0 && n_left_to_next > 0)
2123         {
2124           u32 bi0;
2125           vlib_buffer_t *b0;
2126           ip6_header_t *ip0 = 0;
2127           ip6_sr_header_t *sr0;
2128           ethernet_header_t *en0;
2129           ip6_sr_policy_t *sp0;
2130           ip6_sr_sl_t *sl0;
2131           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2132           u32 flow_label0;
2133
2134           bi0 = from[0];
2135           to_next[0] = bi0;
2136           from += 1;
2137           to_next += 1;
2138           n_left_from -= 1;
2139           n_left_to_next -= 1;
2140           b0 = vlib_get_buffer (vm, bi0);
2141
2142           /* Find the SR policy */
2143           sp0 = pool_elt_at_index (sm->sr_policies,
2144                                    sm->sw_iface_sr_policies[vnet_buffer
2145                                                             (b0)->sw_if_index
2146                                                             [VLIB_RX]]);
2147           flow_label0 = l2_flow_hash (b0);
2148
2149           /* In case there is more than one SL, LB among them */
2150           if (vec_len (sp0->segments_lists) == 1)
2151             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2152           else
2153             {
2154               vnet_buffer (b0)->ip.flow_hash = flow_label0;
2155               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2156                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2157                                      (vec_len (sp0->segments_lists) - 1))];
2158             }
2159           sl0 =
2160             pool_elt_at_index (sm->sid_lists,
2161                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2162           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2163                   vec_len (sl0->rewrite));
2164
2165           en0 = vlib_buffer_get_current (b0);
2166
2167           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2168                             sl0->rewrite, vec_len (sl0->rewrite));
2169
2170           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2171
2172           ip0 = vlib_buffer_get_current (b0);
2173
2174           ip0->payload_length =
2175             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2176
2177           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2178             {
2179               sr0 = (void *) (ip0 + 1);
2180               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2181             }
2182           else
2183             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2184
2185           ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2186             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2187
2188           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2189               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2190             {
2191               sr_policy_rewrite_trace_t *tr =
2192                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2193               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2194                                 sizeof (tr->src.as_u8));
2195               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2196                                 sizeof (tr->dst.as_u8));
2197             }
2198
2199           encap_pkts++;
2200           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2201                                            n_left_to_next, bi0, next0);
2202         }
2203
2204       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2205     }
2206
2207   /* Update counters */
2208   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2209                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2210                                encap_pkts);
2211   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2212                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2213                                bsid_pkts);
2214
2215   return from_frame->n_vectors;
2216 }
2217
2218 /* *INDENT-OFF* */
2219 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2220   .function = sr_policy_rewrite_encaps_l2,
2221   .name = "sr-pl-rewrite-encaps-l2",
2222   .vector_size = sizeof (u32),
2223   .format_trace = format_sr_policy_rewrite_trace,
2224   .type = VLIB_NODE_TYPE_INTERNAL,
2225   .n_errors = SR_POLICY_REWRITE_N_ERROR,
2226   .error_strings = sr_policy_rewrite_error_strings,
2227   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2228   .next_nodes = {
2229 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2230     foreach_sr_policy_rewrite_next
2231 #undef _
2232   },
2233 };
2234 /* *INDENT-ON* */
2235
2236 /**
2237  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2238  */
2239 static uword
2240 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2241                           vlib_frame_t * from_frame)
2242 {
2243   ip6_sr_main_t *sm = &sr_main;
2244   u32 n_left_from, next_index, *from, *to_next;
2245
2246   from = vlib_frame_vector_args (from_frame);
2247   n_left_from = from_frame->n_vectors;
2248
2249   next_index = node->cached_next_index;
2250
2251   int insert_pkts = 0, bsid_pkts = 0;
2252
2253   while (n_left_from > 0)
2254     {
2255       u32 n_left_to_next;
2256
2257       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2258
2259       /* Quad - Loop */
2260       while (n_left_from >= 8 && n_left_to_next >= 4)
2261         {
2262           u32 bi0, bi1, bi2, bi3;
2263           vlib_buffer_t *b0, *b1, *b2, *b3;
2264           u32 next0, next1, next2, next3;
2265           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2266           ip6_header_t *ip0, *ip1, *ip2, *ip3;
2267           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2268           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2269           u16 new_l0, new_l1, new_l2, new_l3;
2270
2271           /* Prefetch next iteration. */
2272           {
2273             vlib_buffer_t *p4, *p5, *p6, *p7;
2274
2275             p4 = vlib_get_buffer (vm, from[4]);
2276             p5 = vlib_get_buffer (vm, from[5]);
2277             p6 = vlib_get_buffer (vm, from[6]);
2278             p7 = vlib_get_buffer (vm, from[7]);
2279
2280             /* Prefetch the buffer header and packet for the N+2 loop iteration */
2281             vlib_prefetch_buffer_header (p4, LOAD);
2282             vlib_prefetch_buffer_header (p5, LOAD);
2283             vlib_prefetch_buffer_header (p6, LOAD);
2284             vlib_prefetch_buffer_header (p7, LOAD);
2285
2286             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2287             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2288             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2289             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2290           }
2291
2292           to_next[0] = bi0 = from[0];
2293           to_next[1] = bi1 = from[1];
2294           to_next[2] = bi2 = from[2];
2295           to_next[3] = bi3 = from[3];
2296           from += 4;
2297           to_next += 4;
2298           n_left_from -= 4;
2299           n_left_to_next -= 4;
2300
2301           b0 = vlib_get_buffer (vm, bi0);
2302           b1 = vlib_get_buffer (vm, bi1);
2303           b2 = vlib_get_buffer (vm, bi2);
2304           b3 = vlib_get_buffer (vm, bi3);
2305
2306           sl0 =
2307             pool_elt_at_index (sm->sid_lists,
2308                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2309           sl1 =
2310             pool_elt_at_index (sm->sid_lists,
2311                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2312           sl2 =
2313             pool_elt_at_index (sm->sid_lists,
2314                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2315           sl3 =
2316             pool_elt_at_index (sm->sid_lists,
2317                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2318           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2319                   vec_len (sl0->rewrite));
2320           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2321                   vec_len (sl1->rewrite));
2322           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2323                   vec_len (sl2->rewrite));
2324           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2325                   vec_len (sl3->rewrite));
2326
2327           ip0 = vlib_buffer_get_current (b0);
2328           ip1 = vlib_buffer_get_current (b1);
2329           ip2 = vlib_buffer_get_current (b2);
2330           ip3 = vlib_buffer_get_current (b3);
2331
2332           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2333             sr0 =
2334               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2335                                    ip6_ext_header_len (ip0 + 1));
2336           else
2337             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2338
2339           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2340             sr1 =
2341               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2342                                    ip6_ext_header_len (ip1 + 1));
2343           else
2344             sr1 = (ip6_sr_header_t *) (ip1 + 1);
2345
2346           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2347             sr2 =
2348               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2349                                    ip6_ext_header_len (ip2 + 1));
2350           else
2351             sr2 = (ip6_sr_header_t *) (ip2 + 1);
2352
2353           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2354             sr3 =
2355               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2356                                    ip6_ext_header_len (ip3 + 1));
2357           else
2358             sr3 = (ip6_sr_header_t *) (ip3 + 1);
2359
2360           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2361                             (void *) sr0 - (void *) ip0);
2362           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2363                             (void *) sr1 - (void *) ip1);
2364           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2365                             (void *) sr2 - (void *) ip2);
2366           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2367                             (void *) sr3 - (void *) ip3);
2368
2369           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2370                             sl0->rewrite, vec_len (sl0->rewrite));
2371           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2372                             sl1->rewrite, vec_len (sl1->rewrite));
2373           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2374                             sl2->rewrite, vec_len (sl2->rewrite));
2375           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2376                             sl3->rewrite, vec_len (sl3->rewrite));
2377
2378           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2379           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2380           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2381           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2382
2383           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2384           ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2385           ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2386           ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2387
2388           ip0->hop_limit -= 1;
2389           ip1->hop_limit -= 1;
2390           ip2->hop_limit -= 1;
2391           ip3->hop_limit -= 1;
2392
2393           new_l0 =
2394             clib_net_to_host_u16 (ip0->payload_length) +
2395             vec_len (sl0->rewrite);
2396           new_l1 =
2397             clib_net_to_host_u16 (ip1->payload_length) +
2398             vec_len (sl1->rewrite);
2399           new_l2 =
2400             clib_net_to_host_u16 (ip2->payload_length) +
2401             vec_len (sl2->rewrite);
2402           new_l3 =
2403             clib_net_to_host_u16 (ip3->payload_length) +
2404             vec_len (sl3->rewrite);
2405
2406           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2407           ip1->payload_length = clib_host_to_net_u16 (new_l1);
2408           ip2->payload_length = clib_host_to_net_u16 (new_l2);
2409           ip3->payload_length = clib_host_to_net_u16 (new_l3);
2410
2411           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2412           sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2413           sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2414           sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2415
2416           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2417           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2418           sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2419           sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2420           sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2421           sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2422           sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2423           sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2424
2425           ip0->dst_address.as_u64[0] =
2426             (sr0->segments + sr0->segments_left)->as_u64[0];
2427           ip0->dst_address.as_u64[1] =
2428             (sr0->segments + sr0->segments_left)->as_u64[1];
2429           ip1->dst_address.as_u64[0] =
2430             (sr1->segments + sr1->segments_left)->as_u64[0];
2431           ip1->dst_address.as_u64[1] =
2432             (sr1->segments + sr1->segments_left)->as_u64[1];
2433           ip2->dst_address.as_u64[0] =
2434             (sr2->segments + sr2->segments_left)->as_u64[0];
2435           ip2->dst_address.as_u64[1] =
2436             (sr2->segments + sr2->segments_left)->as_u64[1];
2437           ip3->dst_address.as_u64[0] =
2438             (sr3->segments + sr3->segments_left)->as_u64[0];
2439           ip3->dst_address.as_u64[1] =
2440             (sr3->segments + sr3->segments_left)->as_u64[1];
2441
2442           ip6_ext_header_t *ip_ext;
2443           if (ip0 + 1 == (void *) sr0)
2444             {
2445               sr0->protocol = ip0->protocol;
2446               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2447             }
2448           else
2449             {
2450               ip_ext = (void *) (ip0 + 1);
2451               sr0->protocol = ip_ext->next_hdr;
2452               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2453             }
2454
2455           if (ip1 + 1 == (void *) sr1)
2456             {
2457               sr1->protocol = ip1->protocol;
2458               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2459             }
2460           else
2461             {
2462               ip_ext = (void *) (ip2 + 1);
2463               sr2->protocol = ip_ext->next_hdr;
2464               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2465             }
2466
2467           if (ip2 + 1 == (void *) sr2)
2468             {
2469               sr2->protocol = ip2->protocol;
2470               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2471             }
2472           else
2473             {
2474               ip_ext = (void *) (ip2 + 1);
2475               sr2->protocol = ip_ext->next_hdr;
2476               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2477             }
2478
2479           if (ip3 + 1 == (void *) sr3)
2480             {
2481               sr3->protocol = ip3->protocol;
2482               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2483             }
2484           else
2485             {
2486               ip_ext = (void *) (ip3 + 1);
2487               sr3->protocol = ip_ext->next_hdr;
2488               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2489             }
2490
2491           insert_pkts += 4;
2492
2493           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2494             {
2495               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2496                 {
2497                   sr_policy_rewrite_trace_t *tr =
2498                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2499                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2500                                     sizeof (tr->src.as_u8));
2501                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2502                                     sizeof (tr->dst.as_u8));
2503                 }
2504
2505               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2506                 {
2507                   sr_policy_rewrite_trace_t *tr =
2508                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2509                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2510                                     sizeof (tr->src.as_u8));
2511                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2512                                     sizeof (tr->dst.as_u8));
2513                 }
2514
2515               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2516                 {
2517                   sr_policy_rewrite_trace_t *tr =
2518                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2519                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2520                                     sizeof (tr->src.as_u8));
2521                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2522                                     sizeof (tr->dst.as_u8));
2523                 }
2524
2525               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2526                 {
2527                   sr_policy_rewrite_trace_t *tr =
2528                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2529                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2530                                     sizeof (tr->src.as_u8));
2531                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2532                                     sizeof (tr->dst.as_u8));
2533                 }
2534             }
2535
2536           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2537                                            n_left_to_next, bi0, bi1, bi2, bi3,
2538                                            next0, next1, next2, next3);
2539         }
2540
2541       /* Single loop for potentially the last three packets */
2542       while (n_left_from > 0 && n_left_to_next > 0)
2543         {
2544           u32 bi0;
2545           vlib_buffer_t *b0;
2546           ip6_header_t *ip0 = 0;
2547           ip6_sr_header_t *sr0 = 0;
2548           ip6_sr_sl_t *sl0;
2549           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2550           u16 new_l0 = 0;
2551
2552           bi0 = from[0];
2553           to_next[0] = bi0;
2554           from += 1;
2555           to_next += 1;
2556           n_left_from -= 1;
2557           n_left_to_next -= 1;
2558
2559           b0 = vlib_get_buffer (vm, bi0);
2560           sl0 =
2561             pool_elt_at_index (sm->sid_lists,
2562                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2563           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2564                   vec_len (sl0->rewrite));
2565
2566           ip0 = vlib_buffer_get_current (b0);
2567
2568           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2569             sr0 =
2570               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2571                                    ip6_ext_header_len (ip0 + 1));
2572           else
2573             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2574
2575           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2576                             (void *) sr0 - (void *) ip0);
2577           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2578                             sl0->rewrite, vec_len (sl0->rewrite));
2579
2580           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2581
2582           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2583           ip0->hop_limit -= 1;
2584           new_l0 =
2585             clib_net_to_host_u16 (ip0->payload_length) +
2586             vec_len (sl0->rewrite);
2587           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2588
2589           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2590           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2591           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2592
2593           ip0->dst_address.as_u64[0] =
2594             (sr0->segments + sr0->segments_left)->as_u64[0];
2595           ip0->dst_address.as_u64[1] =
2596             (sr0->segments + sr0->segments_left)->as_u64[1];
2597
2598           if (ip0 + 1 == (void *) sr0)
2599             {
2600               sr0->protocol = ip0->protocol;
2601               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2602             }
2603           else
2604             {
2605               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2606               sr0->protocol = ip_ext->next_hdr;
2607               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2608             }
2609
2610           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2611               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2612             {
2613               sr_policy_rewrite_trace_t *tr =
2614                 vlib_add_trace (vm, node, b0, sizeof (*tr));
2615               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2616                                 sizeof (tr->src.as_u8));
2617               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2618                                 sizeof (tr->dst.as_u8));
2619             }
2620
2621           insert_pkts++;
2622
2623           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2624                                            n_left_to_next, bi0, next0);
2625         }
2626
2627       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2628     }
2629
2630   /* Update counters */
2631   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2632                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2633                                insert_pkts);
2634   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2635                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2636                                bsid_pkts);
2637   return from_frame->n_vectors;
2638 }
2639
2640 /* *INDENT-OFF* */
2641 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2642   .function = sr_policy_rewrite_insert,
2643   .name = "sr-pl-rewrite-insert",
2644   .vector_size = sizeof (u32),
2645   .format_trace = format_sr_policy_rewrite_trace,
2646   .type = VLIB_NODE_TYPE_INTERNAL,
2647   .n_errors = SR_POLICY_REWRITE_N_ERROR,
2648   .error_strings = sr_policy_rewrite_error_strings,
2649   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2650   .next_nodes = {
2651 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2652     foreach_sr_policy_rewrite_next
2653 #undef _
2654   },
2655 };
2656 /* *INDENT-ON* */
2657
2658 /**
2659  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2660  */
2661 static uword
2662 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2663                             vlib_frame_t * from_frame)
2664 {
2665   ip6_sr_main_t *sm = &sr_main;
2666   u32 n_left_from, next_index, *from, *to_next;
2667
2668   from = vlib_frame_vector_args (from_frame);
2669   n_left_from = from_frame->n_vectors;
2670
2671   next_index = node->cached_next_index;
2672
2673   int insert_pkts = 0, bsid_pkts = 0;
2674
2675   while (n_left_from > 0)
2676     {
2677       u32 n_left_to_next;
2678
2679       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2680
2681       /* Quad - Loop */
2682       while (n_left_from >= 8 && n_left_to_next >= 4)
2683         {
2684           u32 bi0, bi1, bi2, bi3;
2685           vlib_buffer_t *b0, *b1, *b2, *b3;
2686           u32 next0, next1, next2, next3;
2687           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2688           ip6_header_t *ip0, *ip1, *ip2, *ip3;
2689           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2690           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2691           u16 new_l0, new_l1, new_l2, new_l3;
2692
2693           /* Prefetch next iteration. */
2694           {
2695             vlib_buffer_t *p4, *p5, *p6, *p7;
2696
2697             p4 = vlib_get_buffer (vm, from[4]);
2698             p5 = vlib_get_buffer (vm, from[5]);
2699             p6 = vlib_get_buffer (vm, from[6]);
2700             p7 = vlib_get_buffer (vm, from[7]);
2701
2702             /* Prefetch the buffer header and packet for the N+2 loop iteration */
2703             vlib_prefetch_buffer_header (p4, LOAD);
2704             vlib_prefetch_buffer_header (p5, LOAD);
2705             vlib_prefetch_buffer_header (p6, LOAD);
2706             vlib_prefetch_buffer_header (p7, LOAD);
2707
2708             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2709             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2710             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2711             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2712           }
2713
2714           to_next[0] = bi0 = from[0];
2715           to_next[1] = bi1 = from[1];
2716           to_next[2] = bi2 = from[2];
2717           to_next[3] = bi3 = from[3];
2718           from += 4;
2719           to_next += 4;
2720           n_left_from -= 4;
2721           n_left_to_next -= 4;
2722
2723           b0 = vlib_get_buffer (vm, bi0);
2724           b1 = vlib_get_buffer (vm, bi1);
2725           b2 = vlib_get_buffer (vm, bi2);
2726           b3 = vlib_get_buffer (vm, bi3);
2727
2728           sl0 =
2729             pool_elt_at_index (sm->sid_lists,
2730                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2731           sl1 =
2732             pool_elt_at_index (sm->sid_lists,
2733                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2734           sl2 =
2735             pool_elt_at_index (sm->sid_lists,
2736                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2737           sl3 =
2738             pool_elt_at_index (sm->sid_lists,
2739                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2740           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2741                   vec_len (sl0->rewrite_bsid));
2742           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2743                   vec_len (sl1->rewrite_bsid));
2744           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2745                   vec_len (sl2->rewrite_bsid));
2746           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2747                   vec_len (sl3->rewrite_bsid));
2748
2749           ip0 = vlib_buffer_get_current (b0);
2750           ip1 = vlib_buffer_get_current (b1);
2751           ip2 = vlib_buffer_get_current (b2);
2752           ip3 = vlib_buffer_get_current (b3);
2753
2754           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2755             sr0 =
2756               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2757                                    ip6_ext_header_len (ip0 + 1));
2758           else
2759             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2760
2761           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2762             sr1 =
2763               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2764                                    ip6_ext_header_len (ip1 + 1));
2765           else
2766             sr1 = (ip6_sr_header_t *) (ip1 + 1);
2767
2768           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2769             sr2 =
2770               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2771                                    ip6_ext_header_len (ip2 + 1));
2772           else
2773             sr2 = (ip6_sr_header_t *) (ip2 + 1);
2774
2775           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2776             sr3 =
2777               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2778                                    ip6_ext_header_len (ip3 + 1));
2779           else
2780             sr3 = (ip6_sr_header_t *) (ip3 + 1);
2781
2782           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2783                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
2784           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2785                             (u8 *) ip1, (void *) sr1 - (void *) ip1);
2786           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2787                             (u8 *) ip2, (void *) sr2 - (void *) ip2);
2788           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2789                             (u8 *) ip3, (void *) sr3 - (void *) ip3);
2790
2791           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2792                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2793           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2794                             sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2795           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2796                             sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2797           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2798                             sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2799
2800           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2801           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2802           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2803           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2804
2805           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2806           ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2807           ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2808           ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2809
2810           ip0->hop_limit -= 1;
2811           ip1->hop_limit -= 1;
2812           ip2->hop_limit -= 1;
2813           ip3->hop_limit -= 1;
2814
2815           new_l0 =
2816             clib_net_to_host_u16 (ip0->payload_length) +
2817             vec_len (sl0->rewrite_bsid);
2818           new_l1 =
2819             clib_net_to_host_u16 (ip1->payload_length) +
2820             vec_len (sl1->rewrite_bsid);
2821           new_l2 =
2822             clib_net_to_host_u16 (ip2->payload_length) +
2823             vec_len (sl2->rewrite_bsid);
2824           new_l3 =
2825             clib_net_to_host_u16 (ip3->payload_length) +
2826             vec_len (sl3->rewrite_bsid);
2827
2828           ip0->payload_length = clib_host_to_net_u16 (new_l0);
2829           ip1->payload_length = clib_host_to_net_u16 (new_l1);
2830           ip2->payload_length = clib_host_to_net_u16 (new_l2);
2831           ip3->payload_length = clib_host_to_net_u16 (new_l3);
2832
2833           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2834           sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2835           sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2836           sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2837
2838           ip0->dst_address.as_u64[0] =
2839             (sr0->segments + sr0->segments_left)->as_u64[0];
2840           ip0->dst_address.as_u64[1] =
2841             (sr0->segments + sr0->segments_left)->as_u64[1];
2842           ip1->dst_address.as_u64[0] =
2843             (sr1->segments + sr1->segments_left)->as_u64[0];
2844           ip1->dst_address.as_u64[1] =
2845             (sr1->segments + sr1->segments_left)->as_u64[1];
2846           ip2->dst_address.as_u64[0] =
2847             (sr2->segments + sr2->segments_left)->as_u64[0];
2848           ip2->dst_address.as_u64[1] =
2849             (sr2->segments + sr2->segments_left)->as_u64[1];
2850           ip3->dst_address.as_u64[0] =
2851             (sr3->segments + sr3->segments_left)->as_u64[0];
2852           ip3->dst_address.as_u64[1] =
2853             (sr3->segments + sr3->segments_left)->as_u64[1];
2854
2855           ip6_ext_header_t *ip_ext;
2856           if (ip0 + 1 == (void *) sr0)
2857             {
2858               sr0->protocol = ip0->protocol;
2859               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2860             }
2861           else
2862             {
2863               ip_ext = (void *) (ip0 + 1);
2864               sr0->protocol = ip_ext->next_hdr;
2865               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2866             }
2867
2868           if (ip1 + 1 == (void *) sr1)
2869             {
2870               sr1->protocol = ip1->protocol;
2871               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2872             }
2873           else
2874             {
2875               ip_ext = (void *) (ip2 + 1);
2876               sr2->protocol = ip_ext->next_hdr;
2877               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2878             }
2879
2880           if (ip2 + 1 == (void *) sr2)
2881             {
2882               sr2->protocol = ip2->protocol;
2883               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2884             }
2885           else
2886             {
2887               ip_ext = (void *) (ip2 + 1);
2888               sr2->protocol = ip_ext->next_hdr;
2889               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2890             }
2891
2892           if (ip3 + 1 == (void *) sr3)
2893             {
2894               sr3->protocol = ip3->protocol;
2895               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2896             }
2897           else
2898             {
2899               ip_ext = (void *) (ip3 + 1);
2900               sr3->protocol = ip_ext->next_hdr;
2901               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2902             }
2903
2904           insert_pkts += 4;
2905
2906           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2907             {
2908               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2909                 {
2910                   sr_policy_rewrite_trace_t *tr =
2911                     vlib_add_trace (vm, node, b0, sizeof (*tr));
2912                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2913                                     sizeof (tr->src.as_u8));
2914                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2915                                     sizeof (tr->dst.as_u8));
2916                 }
2917
2918               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2919                 {
2920                   sr_policy_rewrite_trace_t *tr =
2921                     vlib_add_trace (vm, node, b1, sizeof (*tr));
2922                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2923                                     sizeof (tr->src.as_u8));
2924                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2925                                     sizeof (tr->dst.as_u8));
2926                 }
2927
2928               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2929                 {
2930                   sr_policy_rewrite_trace_t *tr =
2931                     vlib_add_trace (vm, node, b2, sizeof (*tr));
2932                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2933                                     sizeof (tr->src.as_u8));
2934                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2935                                     sizeof (tr->dst.as_u8));
2936                 }
2937
2938               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2939                 {
2940                   sr_policy_rewrite_trace_t *tr =
2941                     vlib_add_trace (vm, node, b3, sizeof (*tr));
2942                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2943                                     sizeof (tr->src.as_u8));
2944                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2945                                     sizeof (tr->dst.as_u8));
2946                 }
2947             }
2948
2949           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2950                                            n_left_to_next, bi0, bi1, bi2, bi3,
2951                                            next0, next1, next2, next3);
2952         }
2953
2954       /* Single loop for potentially the last three packets */
2955       while (n_left_from > 0 && n_left_to_next > 0)
2956         {
2957           u32 bi0;
2958           vlib_buffer_t *b0;
2959           ip6_header_t *ip0 = 0;
2960           ip6_sr_header_t *sr0 = 0;
2961           ip6_sr_sl_t *sl0;
2962           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2963           u16 new_l0 = 0;
2964
2965           bi0 = from[0];
2966           to_next[0] = bi0;
2967           from += 1;
2968           to_next += 1;
2969           n_left_from -= 1;
2970           n_left_to_next -= 1;
2971
2972           b0 = vlib_get_buffer (vm, bi0);
2973           sl0 =
2974             pool_elt_at_index (sm->sid_lists,
2975                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2976           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977                   vec_len (sl0->rewrite_bsid));
2978
2979           ip0 = vlib_buffer_get_current (b0);
2980
2981           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2982             sr0 =
2983               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2984                                    ip6_ext_header_len (ip0 + 1));
2985           else
2986             sr0 = (ip6_sr_header_t *) (ip0 + 1);
2987
2988           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2989                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
2990           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2991                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2992
2993           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2994
2995           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2996           ip0->hop_limit -= 1;
2997           new_l0 =
2998             clib_net_to_host_u16 (ip0->payload_length) +
2999             vec_len (sl0->rewrite_bsid);
3000           ip0->payload_length = clib_host_to_net_u16 (new_l0);
3001
3002           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3003
3004           ip0->dst_address.as_u64[0] =
3005             (sr0->segments + sr0->segments_left)->as_u64[0];
3006           ip0->dst_address.as_u64[1] =
3007             (sr0->segments + sr0->segments_left)->as_u64[1];
3008
3009           if (ip0 + 1 == (void *) sr0)
3010             {
3011               sr0->protocol = ip0->protocol;
3012               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3013             }
3014           else
3015             {
3016               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3017               sr0->protocol = ip_ext->next_hdr;
3018               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3019             }
3020
3021           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3022               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3023             {
3024               sr_policy_rewrite_trace_t *tr =
3025                 vlib_add_trace (vm, node, b0, sizeof (*tr));
3026               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3027                                 sizeof (tr->src.as_u8));
3028               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3029                                 sizeof (tr->dst.as_u8));
3030             }
3031
3032           insert_pkts++;
3033
3034           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3035                                            n_left_to_next, bi0, next0);
3036         }
3037
3038       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3039     }
3040
3041   /* Update counters */
3042   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3043                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3044                                insert_pkts);
3045   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3046                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3047                                bsid_pkts);
3048   return from_frame->n_vectors;
3049 }
3050
3051 /* *INDENT-OFF* */
3052 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3053   .function = sr_policy_rewrite_b_insert,
3054   .name = "sr-pl-rewrite-b-insert",
3055   .vector_size = sizeof (u32),
3056   .format_trace = format_sr_policy_rewrite_trace,
3057   .type = VLIB_NODE_TYPE_INTERNAL,
3058   .n_errors = SR_POLICY_REWRITE_N_ERROR,
3059   .error_strings = sr_policy_rewrite_error_strings,
3060   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3061   .next_nodes = {
3062 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3063     foreach_sr_policy_rewrite_next
3064 #undef _
3065   },
3066 };
3067 /* *INDENT-ON* */
3068
3069 /**
3070  * @brief Function BSID encapsulation
3071  */
3072 static_always_inline void
3073 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3074                                 vlib_buffer_t * b0,
3075                                 ip6_header_t * ip0,
3076                                 ip6_sr_header_t * sr0, u32 * next0)
3077 {
3078   ip6_address_t *new_dst0;
3079
3080   if (PREDICT_FALSE (!sr0))
3081     goto error_bsid_encaps;
3082
3083   if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3084     {
3085       if (PREDICT_TRUE (sr0->segments_left != 0))
3086         {
3087           sr0->segments_left -= 1;
3088           new_dst0 = (ip6_address_t *) (sr0->segments);
3089           new_dst0 += sr0->segments_left;
3090           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3091           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3092           return;
3093         }
3094     }
3095
3096 error_bsid_encaps:
3097   *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3098   b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3099 }
3100
3101 /**
3102  * @brief Graph node for applying a SR policy BSID - Encapsulation
3103  */
3104 static uword
3105 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3106                             vlib_frame_t * from_frame)
3107 {
3108   ip6_sr_main_t *sm = &sr_main;
3109   u32 n_left_from, next_index, *from, *to_next;
3110
3111   from = vlib_frame_vector_args (from_frame);
3112   n_left_from = from_frame->n_vectors;
3113
3114   next_index = node->cached_next_index;
3115
3116   int encap_pkts = 0, bsid_pkts = 0;
3117
3118   while (n_left_from > 0)
3119     {
3120       u32 n_left_to_next;
3121
3122       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3123
3124       /* Quad - Loop */
3125       while (n_left_from >= 8 && n_left_to_next >= 4)
3126         {
3127           u32 bi0, bi1, bi2, bi3;
3128           vlib_buffer_t *b0, *b1, *b2, *b3;
3129           u32 next0, next1, next2, next3;
3130           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3131           ip6_header_t *ip0, *ip1, *ip2, *ip3;
3132           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3133           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3134           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3135
3136           /* Prefetch next iteration. */
3137           {
3138             vlib_buffer_t *p4, *p5, *p6, *p7;
3139
3140             p4 = vlib_get_buffer (vm, from[4]);
3141             p5 = vlib_get_buffer (vm, from[5]);
3142             p6 = vlib_get_buffer (vm, from[6]);
3143             p7 = vlib_get_buffer (vm, from[7]);
3144
3145             /* Prefetch the buffer header and packet for the N+2 loop iteration */
3146             vlib_prefetch_buffer_header (p4, LOAD);
3147             vlib_prefetch_buffer_header (p5, LOAD);
3148             vlib_prefetch_buffer_header (p6, LOAD);
3149             vlib_prefetch_buffer_header (p7, LOAD);
3150
3151             CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3152             CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3153             CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3154             CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3155           }
3156
3157           to_next[0] = bi0 = from[0];
3158           to_next[1] = bi1 = from[1];
3159           to_next[2] = bi2 = from[2];
3160           to_next[3] = bi3 = from[3];
3161           from += 4;
3162           to_next += 4;
3163           n_left_from -= 4;
3164           n_left_to_next -= 4;
3165
3166           b0 = vlib_get_buffer (vm, bi0);
3167           b1 = vlib_get_buffer (vm, bi1);
3168           b2 = vlib_get_buffer (vm, bi2);
3169           b3 = vlib_get_buffer (vm, bi3);
3170
3171           sl0 =
3172             pool_elt_at_index (sm->sid_lists,
3173                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3174           sl1 =
3175             pool_elt_at_index (sm->sid_lists,
3176                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3177           sl2 =
3178             pool_elt_at_index (sm->sid_lists,
3179                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3180           sl3 =
3181             pool_elt_at_index (sm->sid_lists,
3182                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3183           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3184                   vec_len (sl0->rewrite));
3185           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3186                   vec_len (sl1->rewrite));
3187           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3188                   vec_len (sl2->rewrite));
3189           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3190                   vec_len (sl3->rewrite));
3191
3192           ip0_encap = vlib_buffer_get_current (b0);
3193           ip1_encap = vlib_buffer_get_current (b1);
3194           ip2_encap = vlib_buffer_get_current (b2);
3195           ip3_encap = vlib_buffer_get_current (b3);
3196
3197           sr0 =
3198             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3199                                  NULL);
3200           sr1 =
3201             ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3202                                  NULL);
3203           sr2 =
3204             ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3205                                  NULL);
3206           sr3 =
3207             ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3208                                  NULL);
3209
3210           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3211           end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3212           end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3213           end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3214
3215           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3216                             sl0->rewrite, vec_len (sl0->rewrite));
3217           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3218                             sl1->rewrite, vec_len (sl1->rewrite));
3219           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3220                             sl2->rewrite, vec_len (sl2->rewrite));
3221           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3222                             sl3->rewrite, vec_len (sl3->rewrite));
3223
3224           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3225           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3226           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3227           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3228
3229           ip0 = vlib_buffer_get_current (b0);
3230           ip1 = vlib_buffer_get_current (b1);
3231           ip2 = vlib_buffer_get_current (b2);
3232           ip3 = vlib_buffer_get_current (b3);
3233
3234           encaps_processing_v6 (node, b0, ip0, ip0_encap);
3235           encaps_processing_v6 (node, b1, ip1, ip1_encap);
3236           encaps_processing_v6 (node, b2, ip2, ip2_encap);
3237           encaps_processing_v6 (node, b3, ip3, ip3_encap);
3238
3239           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3240             {
3241               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3242                 {
3243                   sr_policy_rewrite_trace_t *tr =
3244                     vlib_add_trace (vm, node, b0, sizeof (*tr));
3245                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3246                                     sizeof (tr->src.as_u8));
3247                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3248                                     sizeof (tr->dst.as_u8));
3249                 }
3250
3251               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3252                 {
3253                   sr_policy_rewrite_trace_t *tr =
3254                     vlib_add_trace (vm, node, b1, sizeof (*tr));
3255                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3256                                     sizeof (tr->src.as_u8));
3257                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3258                                     sizeof (tr->dst.as_u8));
3259                 }
3260
3261               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3262                 {
3263                   sr_policy_rewrite_trace_t *tr =
3264                     vlib_add_trace (vm, node, b2, sizeof (*tr));
3265                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3266                                     sizeof (tr->src.as_u8));
3267                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3268                                     sizeof (tr->dst.as_u8));
3269                 }
3270
3271               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3272                 {
3273                   sr_policy_rewrite_trace_t *tr =
3274                     vlib_add_trace (vm, node, b3, sizeof (*tr));
3275                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3276                                     sizeof (tr->src.as_u8));
3277                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3278                                     sizeof (tr->dst.as_u8));
3279                 }
3280             }
3281
3282           encap_pkts += 4;
3283           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3284                                            n_left_to_next, bi0, bi1, bi2, bi3,
3285                                            next0, next1, next2, next3);
3286         }
3287
3288       /* Single loop for potentially the last three packets */
3289       while (n_left_from > 0 && n_left_to_next > 0)
3290         {
3291           u32 bi0;
3292           vlib_buffer_t *b0;
3293           ip6_header_t *ip0 = 0, *ip0_encap = 0;
3294           ip6_sr_header_t *sr0;
3295           ip6_sr_sl_t *sl0;
3296           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3297
3298           bi0 = from[0];
3299           to_next[0] = bi0;
3300           from += 1;
3301           to_next += 1;
3302           n_left_from -= 1;
3303           n_left_to_next -= 1;
3304           b0 = vlib_get_buffer (vm, bi0);
3305
3306           sl0 =
3307             pool_elt_at_index (sm->sid_lists,
3308                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3309           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3310                   vec_len (sl0->rewrite));
3311
3312           ip0_encap = vlib_buffer_get_current (b0);
3313           sr0 =
3314             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3315                                  NULL);
3316           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3317
3318           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3319                             sl0->rewrite, vec_len (sl0->rewrite));
3320           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3321
3322           ip0 = vlib_buffer_get_current (b0);
3323
3324           encaps_processing_v6 (node, b0, ip0, ip0_encap);
3325
3326           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3327               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3328             {
3329               sr_policy_rewrite_trace_t *tr =
3330                 vlib_add_trace (vm, node, b0, sizeof (*tr));
3331               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3332                                 sizeof (tr->src.as_u8));
3333               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3334                                 sizeof (tr->dst.as_u8));
3335             }
3336
3337           encap_pkts++;
3338           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3339                                            n_left_to_next, bi0, next0);
3340         }
3341
3342       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3343     }
3344
3345   /* Update counters */
3346   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3347                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3348                                encap_pkts);
3349   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3350                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3351                                bsid_pkts);
3352
3353   return from_frame->n_vectors;
3354 }
3355
3356 /* *INDENT-OFF* */
3357 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3358   .function = sr_policy_rewrite_b_encaps,
3359   .name = "sr-pl-rewrite-b-encaps",
3360   .vector_size = sizeof (u32),
3361   .format_trace = format_sr_policy_rewrite_trace,
3362   .type = VLIB_NODE_TYPE_INTERNAL,
3363   .n_errors = SR_POLICY_REWRITE_N_ERROR,
3364   .error_strings = sr_policy_rewrite_error_strings,
3365   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3366   .next_nodes = {
3367 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3368     foreach_sr_policy_rewrite_next
3369 #undef _
3370   },
3371 };
3372 /* *INDENT-ON* */
3373
3374 /*************************** SR Policy plugins ******************************/
3375 /**
3376  * @brief SR Policy plugin registry
3377  */
3378 int
3379 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3380                              u8 * keyword_str, u8 * def_str,
3381                              u8 * params_str, u8 prefix_length,
3382                              dpo_type_t * dpo,
3383                              format_function_t * ls_format,
3384                              unformat_function_t * ls_unformat,
3385                              sr_p_plugin_callback_t * creation_fn,
3386                              sr_p_plugin_callback_t * removal_fn)
3387 {
3388   ip6_sr_main_t *sm = &sr_main;
3389   uword *p;
3390
3391   sr_policy_fn_registration_t *plugin;
3392
3393   /* Did this function exist? If so update it */
3394   p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3395   if (p)
3396     {
3397       plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3398     }
3399   /* Else create a new one and set hash key */
3400   else
3401     {
3402       pool_get (sm->policy_plugin_functions, plugin);
3403       hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3404                     plugin - sm->policy_plugin_functions);
3405     }
3406
3407   clib_memset (plugin, 0, sizeof (*plugin));
3408
3409   plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3410   plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3411   plugin->prefix_length = prefix_length;
3412   plugin->ls_format = ls_format;
3413   plugin->ls_unformat = ls_unformat;
3414   plugin->creation = creation_fn;
3415   plugin->removal = removal_fn;
3416   clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3417   plugin->function_name = format (0, "%s%c", fn_name, 0);
3418   plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3419   plugin->def_str = format (0, "%s%c", def_str, 0);
3420   plugin->params_str = format (0, "%s%c", params_str, 0);
3421
3422   return plugin->sr_policy_function_number;
3423 }
3424
3425 /**
3426  * @brief CLI function to 'show' all available SR LocalSID behaviors
3427  */
3428 static clib_error_t *
3429 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3430                                      unformat_input_t * input,
3431                                      vlib_cli_command_t * cmd)
3432 {
3433   ip6_sr_main_t *sm = &sr_main;
3434   sr_policy_fn_registration_t *plugin;
3435   sr_policy_fn_registration_t **plugins_vec = 0;
3436   int i;
3437
3438   vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3439
3440   /* *INDENT-OFF* */
3441   pool_foreach (plugin, sm->policy_plugin_functions)
3442      { vec_add1 (plugins_vec, plugin); }
3443   /* *INDENT-ON* */
3444
3445   vlib_cli_output (vm, "Plugin behaviors:\n");
3446   for (i = 0; i < vec_len (plugins_vec); i++)
3447     {
3448       plugin = plugins_vec[i];
3449       vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3450                        plugin->def_str);
3451       vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3452     }
3453   return 0;
3454 }
3455
3456 /* *INDENT-OFF* */
3457 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3458   .path = "show sr policy behaviors",
3459   .short_help = "show sr policy behaviors",
3460   .function = show_sr_policy_behaviors_command_fn,
3461 };
3462 /* *INDENT-ON* */
3463
3464 /*************************** SR Segment Lists DPOs ****************************/
3465 static u8 *
3466 format_sr_segment_list_dpo (u8 * s, va_list * args)
3467 {
3468   ip6_sr_main_t *sm = &sr_main;
3469   ip6_address_t *addr;
3470   ip6_sr_sl_t *sl;
3471
3472   index_t index = va_arg (*args, index_t);
3473   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3474   s = format (s, "SR: Segment List index:[%d]", index);
3475   s = format (s, "\n\tSegments:");
3476
3477   sl = pool_elt_at_index (sm->sid_lists, index);
3478
3479   s = format (s, "< ");
3480   vec_foreach (addr, sl->segments)
3481   {
3482     s = format (s, "%U, ", format_ip6_address, addr);
3483   }
3484   s = format (s, "\b\b > - ");
3485   s = format (s, "Weight: %u", sl->weight);
3486
3487   return s;
3488 }
3489
3490 const static dpo_vft_t sr_policy_rewrite_vft = {
3491   .dv_lock = sr_dpo_lock,
3492   .dv_unlock = sr_dpo_unlock,
3493   .dv_format = format_sr_segment_list_dpo,
3494 };
3495
3496 const static char *const sr_pr_encaps_ip6_nodes[] = {
3497   "sr-pl-rewrite-encaps",
3498   NULL,
3499 };
3500
3501 const static char *const sr_pr_encaps_ip4_nodes[] = {
3502   "sr-pl-rewrite-encaps-v4",
3503   NULL,
3504 };
3505
3506 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3507   [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3508   [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3509 };
3510
3511 const static char *const sr_pr_insert_ip6_nodes[] = {
3512   "sr-pl-rewrite-insert",
3513   NULL,
3514 };
3515
3516 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3517   [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3518 };
3519
3520 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3521   "sr-pl-rewrite-b-insert",
3522   NULL,
3523 };
3524
3525 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3526   [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3527 };
3528
3529 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3530   "sr-pl-rewrite-b-encaps",
3531   NULL,
3532 };
3533
3534 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3535   [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3536 };
3537
3538 /********************* SR Policy Rewrite initialization ***********************/
3539 /**
3540  * @brief SR Policy Rewrite initialization
3541  */
3542 clib_error_t *
3543 sr_policy_rewrite_init (vlib_main_t * vm)
3544 {
3545   ip6_sr_main_t *sm = &sr_main;
3546
3547   /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3548   mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3549               sizeof (ip6_address_t));
3550
3551   /* Init SR VPO DPOs type */
3552   sr_pr_encaps_dpo_type =
3553     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3554
3555   sr_pr_insert_dpo_type =
3556     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3557
3558   sr_pr_bsid_encaps_dpo_type =
3559     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3560
3561   sr_pr_bsid_insert_dpo_type =
3562     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3563
3564   /* Register the L2 encaps node used in HW redirect */
3565   sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3566
3567   sm->fib_table_ip6 = (u32) ~ 0;
3568   sm->fib_table_ip4 = (u32) ~ 0;
3569
3570   return 0;
3571 }
3572
3573 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3574
3575
3576 /*
3577 * fd.io coding-style-patch-verification: ON
3578 *
3579 * Local Variables:
3580 * eval: (c-set-style "gnu")
3581 * End:
3582 */