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