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