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