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