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