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