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