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