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