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