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