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