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