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