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