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