2 * sr_policy_rewrite.c: ipv6 sr policy creation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @brief SR policy creation and application
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.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
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)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
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")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
115 static clib_error_t *
116 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
125 return clib_error_return (0, "No address specified");
127 return clib_error_return (0, "No address specified");
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132 .path = "set sr encaps source",
133 .short_help = "set sr encaps source addr <ip6_addr>",
134 .function = set_sr_src_command_fn,
138 /*********************** SR rewrite string computation ************************/
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
142 * @param sl is a vector of IPv6 addresses composing the Segment List
144 * @return precomputed rewrite string for encapsulation
147 compute_rewrite_encaps (ip6_address_t * sl)
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
163 vec_validate (rs, header_length - 1);
165 iph = (ip6_header_t *) rs;
166 iph->ip_version_traffic_class_and_flow_label =
167 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171 iph->protocol = IP_PROTOCOL_IPV6;
172 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
174 srh = (ip6_sr_header_t *) (iph + 1);
175 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176 srh->protocol = IP_PROTOCOL_IPV6;
177 srh->type = ROUTING_HEADER_TYPE_SR;
178 srh->segments_left = vec_len (sl) - 1;
179 srh->first_segment = vec_len (sl) - 1;
180 srh->length = ((sizeof (ip6_sr_header_t) +
181 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
196 * @brief SR rewrite string computation for SRH insertion (inline)
198 * @param sl is a vector of IPv6 addresses composing the Segment List
200 * @return precomputed rewrite string for SRH insertion
203 compute_rewrite_insert (ip6_address_t * sl)
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 srh = (ip6_sr_header_t *) rs;
217 srh->type = ROUTING_HEADER_TYPE_SR;
218 srh->segments_left = vec_len (sl);
219 srh->first_segment = vec_len (sl);
220 srh->length = ((sizeof (ip6_sr_header_t) +
221 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
236 * @param sl is a vector of IPv6 addresses composing the Segment List
238 * @return precomputed rewrite string for SRH insertion with BSID
241 compute_rewrite_bsid (ip6_address_t * sl)
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
252 vec_validate (rs, header_length - 1);
254 srh = (ip6_sr_header_t *) rs;
255 srh->type = ROUTING_HEADER_TYPE_SR;
256 srh->segments_left = vec_len (sl) - 1;
257 srh->first_segment = vec_len (sl) - 1;
258 srh->length = ((sizeof (ip6_sr_header_t) +
259 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
271 /*************************** SR LB helper functions **************************/
273 * @brief Creates a Segment List and adds it to an SR policy
275 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276 * not necessarily unique. Hence there might be two Segment List within the
277 * same SR Policy with exactly the same segments and same weight.
279 * @param sr_policy is the SR policy where the SL will be added
280 * @param sl is a vector of IPv6 addresses composing the Segment List
281 * @param weight is the weight of the SegmentList (for load-balancing purposes)
282 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
284 * @return pointer to the just created segment list
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
298 /* Fill in segment list */
299 segment_list->weight =
300 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301 segment_list->segments = vec_dup (sl);
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
321 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
322 segment_list - sm->sid_lists);
323 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
324 segment_list - sm->sid_lists);
325 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
326 DPO_PROTO_IP6, segment_list - sm->sid_lists);
330 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
331 segment_list - sm->sid_lists);
332 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
333 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 * @brief Updates the Load Balancer after an SR Policy change
342 * @param sr_policy is the modified SR Policy
345 update_lb (ip6_sr_policy_t * sr_policy)
347 flow_hash_config_t fhc;
349 ip6_sr_sl_t *segment_list;
350 ip6_sr_main_t *sm = &sr_main;
351 load_balance_path_t path;
352 path.path_index = FIB_NODE_INDEX_INVALID;
353 load_balance_path_t *ip4_path_vector = 0;
354 load_balance_path_t *ip6_path_vector = 0;
355 load_balance_path_t *b_path_vector = 0;
357 /* In case LB does not exist, create it */
358 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
361 .fp_proto = FIB_PROTOCOL_IP6,
364 .ip6 = sr_policy->bsid,
368 /* Add FIB entry for BSID */
369 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
370 dpo_proto_to_fib (DPO_PROTO_IP6));
372 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
373 load_balance_create (0, DPO_PROTO_IP6, fhc));
375 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
376 load_balance_create (0, DPO_PROTO_IP6, fhc));
378 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
379 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
380 sr_policy->fib_table),
382 FIB_ENTRY_FLAG_EXCLUSIVE,
383 &sr_policy->bsid_dpo);
385 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->ip6_dpo);
391 if (sr_policy->is_encap)
393 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
394 load_balance_create (0, DPO_PROTO_IP4, fhc));
396 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
399 FIB_ENTRY_FLAG_EXCLUSIVE,
400 &sr_policy->ip4_dpo);
405 /* Create the LB path vector */
406 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
407 vec_foreach (sl_index, sr_policy->segments_lists)
409 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
410 path.path_dpo = segment_list->bsid_dpo;
411 path.path_weight = segment_list->weight;
412 vec_add1 (b_path_vector, path);
413 path.path_dpo = segment_list->ip6_dpo;
414 vec_add1 (ip6_path_vector, path);
415 if (sr_policy->is_encap)
417 path.path_dpo = segment_list->ip4_dpo;
418 vec_add1 (ip4_path_vector, path);
422 /* Update LB multipath */
423 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
424 LOAD_BALANCE_FLAG_NONE);
425 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
426 LOAD_BALANCE_FLAG_NONE);
427 if (sr_policy->is_encap)
428 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
429 LOAD_BALANCE_FLAG_NONE);
432 vec_free (b_path_vector);
433 vec_free (ip6_path_vector);
434 vec_free (ip4_path_vector);
439 * @brief Updates the Replicate DPO after an SR Policy change
441 * @param sr_policy is the modified SR Policy (type spray)
444 update_replicate (ip6_sr_policy_t * sr_policy)
447 ip6_sr_sl_t *segment_list;
448 ip6_sr_main_t *sm = &sr_main;
449 load_balance_path_t path;
450 path.path_index = FIB_NODE_INDEX_INVALID;
451 load_balance_path_t *b_path_vector = 0;
452 load_balance_path_t *ip6_path_vector = 0;
453 load_balance_path_t *ip4_path_vector = 0;
455 /* In case LB does not exist, create it */
456 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
458 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
459 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
461 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
462 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
464 /* Update FIB entry's DPO to point to SR without LB */
466 .fp_proto = FIB_PROTOCOL_IP6,
469 .ip6 = sr_policy->bsid,
472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
484 if (sr_policy->is_encap)
486 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
487 replicate_create (0, DPO_PROTO_IP4));
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
498 /* Create the replicate path vector */
499 path.path_weight = 1;
500 vec_foreach (sl_index, sr_policy->segments_lists)
502 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
503 path.path_dpo = segment_list->bsid_dpo;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
514 /* Update replicate multipath */
515 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
516 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
517 if (sr_policy->is_encap)
518 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
521 /******************************* SR rewrite API *******************************/
522 /* Three functions for handling sr policies:
526 * All of them are API. CLI function on sr_policy_command_fn */
529 * @brief Create a new SR policy
531 * @param bsid is the bindingSID of the SR Policy
532 * @param segments is a vector of IPv6 address composing the segment list
533 * @param weight is the weight of the sid list. optional.
534 * @param behavior is the behavior of the SR policy. (default//spray)
535 * @param fib_table is the VRF where to install the FIB entry for the BSID
536 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
538 * @return 0 if correct, else error
541 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
542 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
544 ip6_sr_main_t *sm = &sr_main;
545 ip6_sr_policy_t *sr_policy = 0;
548 /* Search for existing keys (BSID) */
549 p = mhash_get (&sm->sr_policies_index_hash, bsid);
552 /* Add SR policy that already exists; complain */
556 /* Search collision in FIB entries */
557 /* Explanation: It might be possible that some other entity has already
558 * created a route for the BSID. This in theory is impossible, but in
559 * practise we could see it. Assert it and scream if needed */
561 .fp_proto = FIB_PROTOCOL_IP6,
568 /* Lookup the FIB index associated to the table selected */
569 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
570 (fib_table != (u32) ~ 0 ? fib_table : 0));
574 /* Lookup whether there exists an entry for the BSID */
575 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
576 if (FIB_NODE_INDEX_INVALID != fei)
577 return -12; //There is an entry for such lookup
579 /* Add an SR policy object */
580 pool_get (sm->sr_policies, sr_policy);
581 memset (sr_policy, 0, sizeof (*sr_policy));
582 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
583 sr_policy->type = behavior;
584 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
585 sr_policy->is_encap = is_encap;
588 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
591 /* Create a segment list and add the index to the SR policy */
592 create_sl (sr_policy, segments, weight, is_encap);
594 /* If FIB doesnt exist, create them */
595 if (sm->fib_table_ip6 == (u32) ~ 0)
597 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
598 "SRv6 steering of IP6 prefixes through BSIDs");
599 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
600 "SRv6 steering of IP4 prefixes through BSIDs");
603 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
604 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
605 update_lb (sr_policy);
606 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
607 update_replicate (sr_policy);
612 * @brief Delete a SR policy
614 * @param bsid is the bindingSID of the SR Policy
615 * @param index is the index of the SR policy
617 * @return 0 if correct, else error
620 sr_policy_del (ip6_address_t * bsid, u32 index)
622 ip6_sr_main_t *sm = &sr_main;
623 ip6_sr_policy_t *sr_policy = 0;
624 ip6_sr_sl_t *segment_list;
630 p = mhash_get (&sm->sr_policies_index_hash, bsid);
632 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
638 sr_policy = pool_elt_at_index (sm->sr_policies, index);
643 /* Remove BindingSID FIB entry */
645 .fp_proto = FIB_PROTOCOL_IP6,
648 .ip6 = sr_policy->bsid,
653 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
654 sr_policy->fib_table),
655 &pfx, FIB_SOURCE_SR);
657 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
659 if (sr_policy->is_encap)
660 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
662 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
664 dpo_reset (&sr_policy->bsid_dpo);
665 dpo_reset (&sr_policy->ip4_dpo);
666 dpo_reset (&sr_policy->ip6_dpo);
669 /* Clean SID Lists */
670 vec_foreach (sl_index, sr_policy->segments_lists)
672 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
673 vec_free (segment_list->segments);
674 vec_free (segment_list->rewrite);
675 if (!sr_policy->is_encap)
676 vec_free (segment_list->rewrite_bsid);
677 pool_put_index (sm->sid_lists, *sl_index);
680 /* Remove SR policy entry */
681 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
682 pool_put (sm->sr_policies, sr_policy);
684 /* If FIB empty unlock it */
685 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
687 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6);
688 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6);
689 sm->fib_table_ip6 = (u32) ~ 0;
690 sm->fib_table_ip4 = (u32) ~ 0;
697 * @brief Modify an existing SR policy
699 * The possible modifications are adding a new Segment List, modifying an
700 * existing Segment List (modify the weight only) and delete a given
701 * Segment List from the SR Policy.
703 * @param bsid is the bindingSID of the SR Policy
704 * @param index is the index of the SR policy
705 * @param fib_table is the VRF where to install the FIB entry for the BSID
706 * @param operation is the operation to perform (among the top ones)
707 * @param segments is a vector of IPv6 address composing the segment list
708 * @param sl_index is the index of the Segment List to modify/delete
709 * @param weight is the weight of the sid list. optional.
710 * @param is_encap Mode. Encapsulation or SRH insertion.
712 * @return 0 if correct, else error
715 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
716 u8 operation, ip6_address_t * segments, u32 sl_index,
719 ip6_sr_main_t *sm = &sr_main;
720 ip6_sr_policy_t *sr_policy = 0;
721 ip6_sr_sl_t *segment_list;
722 u32 *sl_index_iterate;
727 p = mhash_get (&sm->sr_policies_index_hash, bsid);
729 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
735 sr_policy = pool_elt_at_index (sm->sr_policies, index);
740 if (operation == 1) /* Add SR List to an existing SR policy */
742 /* Create the new SL */
744 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
746 /* Create a new LB DPO */
747 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
748 update_lb (sr_policy);
749 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
750 update_replicate (sr_policy);
752 else if (operation == 2) /* Delete SR List from an existing SR policy */
754 /* Check that currently there are more than one SID list */
755 if (vec_len (sr_policy->segments_lists) == 1)
758 /* Check that the SR list does exist and is assigned to the sr policy */
759 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
760 if (*sl_index_iterate == sl_index)
763 if (*sl_index_iterate != sl_index)
766 /* Remove the lucky SR list that is being kicked out */
767 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
768 vec_free (segment_list->segments);
769 vec_free (segment_list->rewrite);
770 if (!sr_policy->is_encap)
771 vec_free (segment_list->rewrite_bsid);
772 pool_put_index (sm->sid_lists, sl_index);
773 vec_del1 (sr_policy->segments_lists,
774 sl_index_iterate - sr_policy->segments_lists);
776 /* Create a new LB DPO */
777 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
778 update_lb (sr_policy);
779 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
780 update_replicate (sr_policy);
782 else if (operation == 3) /* Modify the weight of an existing SR List */
784 /* Find the corresponding SL */
785 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
786 if (*sl_index_iterate == sl_index)
789 if (*sl_index_iterate != sl_index)
792 /* Change the weight */
793 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
794 segment_list->weight = weight;
797 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
798 update_lb (sr_policy);
800 else /* Incorrect op. */
807 * @brief CLI for 'sr policies' command family
809 static clib_error_t *
810 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
811 vlib_cli_command_t * cmd)
814 char is_del = 0, is_add = 0, is_mod = 0;
816 ip6_address_t bsid, next_address;
817 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
818 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
819 ip6_address_t *segments = 0, *this_seg;
824 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
826 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
828 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
830 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
833 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
835 else if (!is_add && !policy_set
836 && unformat (input, "index %d", &sr_policy_index))
838 else if (unformat (input, "weight %d", &weight));
840 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
842 vec_add2 (segments, this_seg, 1);
843 clib_memcpy (this_seg->as_u8, next_address.as_u8,
846 else if (unformat (input, "add sl"))
848 else if (unformat (input, "del sl index %d", &sl_index))
850 else if (unformat (input, "mod sl index %d", &sl_index))
852 else if (fib_table == (u32) ~ 0
853 && unformat (input, "fib-table %d", &fib_table));
854 else if (unformat (input, "encap"))
856 else if (unformat (input, "insert"))
858 else if (unformat (input, "spray"))
864 if (!is_add && !is_mod && !is_del)
865 return clib_error_return (0, "Incorrect CLI");
868 return clib_error_return (0, "No SR policy BSID or index specified");
872 if (vec_len (segments) == 0)
873 return clib_error_return (0, "No Segment List specified");
874 rv = sr_policy_add (&bsid, segments, weight,
875 (is_spray ? SR_POLICY_TYPE_SPRAY :
876 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
879 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
884 return clib_error_return (0, "No SL modification specified");
885 if (operation != 1 && sl_index == (u32) ~ 0)
886 return clib_error_return (0, "No Segment List index specified");
887 if (operation == 1 && vec_len (segments) == 0)
888 return clib_error_return (0, "No Segment List specified");
889 if (operation == 3 && weight == (u32) ~ 0)
890 return clib_error_return (0, "No new weight for the SL specified");
891 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
892 sr_policy_index, fib_table, operation, segments,
903 return clib_error_return (0,
904 "There is already a FIB entry for the BindingSID address.\n"
905 "The SR policy could not be created.");
907 return clib_error_return (0, "The specified FIB table does not exist.");
909 return clib_error_return (0,
910 "The selected SR policy only contains ONE segment list. "
911 "Please remove the SR policy instead");
913 return clib_error_return (0,
914 "Could not delete the segment list. "
915 "It is not associated with that SR policy.");
917 return clib_error_return (0,
918 "Could not modify the segment list. "
919 "The given SL is not associated with such SR policy.");
921 return clib_error_return (0, "BUG: sr policy returns %d", rv);
927 VLIB_CLI_COMMAND (sr_policy_command, static) = {
929 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
930 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
932 "Manipulation of SR policies.\n"
933 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
934 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
935 "Segment Routing policies might be of type encapsulation or srh insertion\n"
936 "Each SR policy will be associated with a unique BindingSID.\n"
937 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
938 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
939 "The add command will create a SR policy with its first segment list (sl)\n"
940 "The mod command allows you to add, remove, or modify the existing segment lists\n"
941 "within an SR policy.\n"
942 "The del command allows you to delete a SR policy along with all its associated\n"
944 .function = sr_policy_command_fn,
949 * @brief CLI to display onscreen all the SR policies
951 static clib_error_t *
952 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
953 vlib_cli_command_t * cmd)
955 ip6_sr_main_t *sm = &sr_main;
957 ip6_sr_sl_t *segment_list = 0;
958 ip6_sr_policy_t *sr_policy = 0;
959 ip6_sr_policy_t **vec_policies = 0;
964 vlib_cli_output (vm, "SR policies:");
967 pool_foreach (sr_policy, sm->sr_policies,
968 {vec_add1 (vec_policies, sr_policy); } );
971 vec_foreach_index (i, vec_policies)
973 sr_policy = vec_policies[i];
974 vlib_cli_output (vm, "[%u].-\tBSID: %U",
975 (u32) (sr_policy - sm->sr_policies),
976 format_ip6_address, &sr_policy->bsid);
977 vlib_cli_output (vm, "\tBehavior: %s",
978 (sr_policy->is_encap ? "Encapsulation" :
980 vlib_cli_output (vm, "\tType: %s",
982 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
983 vlib_cli_output (vm, "\tFIB table: %u",
984 (sr_policy->fib_table !=
985 (u32) ~ 0 ? sr_policy->fib_table : 0));
986 vlib_cli_output (vm, "\tSegment Lists:");
987 vec_foreach (sl_index, sr_policy->segments_lists)
990 s = format (s, "\t[%u].- ", *sl_index);
991 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
992 s = format (s, "< ");
993 vec_foreach (addr, segment_list->segments)
995 s = format (s, "%U, ", format_ip6_address, addr);
997 s = format (s, "\b\b > ");
998 s = format (s, "weight: %u", segment_list->weight);
999 vlib_cli_output (vm, " %s", s);
1001 vlib_cli_output (vm, "-----------");
1007 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1008 .path = "show sr policies",
1009 .short_help = "show sr policies",
1010 .function = show_sr_policies_command_fn,
1014 /*************************** SR rewrite graph node ****************************/
1016 * @brief Trace for the SR Policy Rewrite graph node
1019 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1022 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1023 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1024 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1027 (s, "SR-policy-rewrite: src %U dst %U",
1028 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1034 * @brief IPv6 encapsulation processing as per RFC2473
1036 static_always_inline void
1037 encaps_processing_v6 (vlib_node_runtime_t * node,
1039 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1043 ip0_encap->hop_limit -= 1;
1045 ip0->payload_length + sizeof (ip6_header_t) +
1046 clib_net_to_host_u16 (ip0_encap->payload_length);
1047 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1048 ip0->ip_version_traffic_class_and_flow_label =
1049 ip0_encap->ip_version_traffic_class_and_flow_label;
1053 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1056 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1057 vlib_frame_t * from_frame)
1059 ip6_sr_main_t *sm = &sr_main;
1060 u32 n_left_from, next_index, *from, *to_next;
1062 from = vlib_frame_vector_args (from_frame);
1063 n_left_from = from_frame->n_vectors;
1065 next_index = node->cached_next_index;
1067 int encap_pkts = 0, bsid_pkts = 0;
1069 while (n_left_from > 0)
1073 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1076 while (n_left_from >= 8 && n_left_to_next >= 4)
1078 u32 bi0, bi1, bi2, bi3;
1079 vlib_buffer_t *b0, *b1, *b2, *b3;
1080 u32 next0, next1, next2, next3;
1081 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1082 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1083 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1084 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1086 /* Prefetch next iteration. */
1088 vlib_buffer_t *p4, *p5, *p6, *p7;
1090 p4 = vlib_get_buffer (vm, from[4]);
1091 p5 = vlib_get_buffer (vm, from[5]);
1092 p6 = vlib_get_buffer (vm, from[6]);
1093 p7 = vlib_get_buffer (vm, from[7]);
1095 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1096 vlib_prefetch_buffer_header (p4, LOAD);
1097 vlib_prefetch_buffer_header (p5, LOAD);
1098 vlib_prefetch_buffer_header (p6, LOAD);
1099 vlib_prefetch_buffer_header (p7, LOAD);
1101 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1102 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1103 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1104 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1107 to_next[0] = bi0 = from[0];
1108 to_next[1] = bi1 = from[1];
1109 to_next[2] = bi2 = from[2];
1110 to_next[3] = bi3 = from[3];
1114 n_left_to_next -= 4;
1116 b0 = vlib_get_buffer (vm, bi0);
1117 b1 = vlib_get_buffer (vm, bi1);
1118 b2 = vlib_get_buffer (vm, bi2);
1119 b3 = vlib_get_buffer (vm, bi3);
1122 pool_elt_at_index (sm->sid_lists,
1123 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1125 pool_elt_at_index (sm->sid_lists,
1126 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1128 pool_elt_at_index (sm->sid_lists,
1129 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1131 pool_elt_at_index (sm->sid_lists,
1132 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1134 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1135 vec_len (sl0->rewrite));
1136 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1137 vec_len (sl1->rewrite));
1138 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1139 vec_len (sl2->rewrite));
1140 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1141 vec_len (sl3->rewrite));
1143 ip0_encap = vlib_buffer_get_current (b0);
1144 ip1_encap = vlib_buffer_get_current (b1);
1145 ip2_encap = vlib_buffer_get_current (b2);
1146 ip3_encap = vlib_buffer_get_current (b3);
1148 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1149 sl0->rewrite, vec_len (sl0->rewrite));
1150 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1151 sl1->rewrite, vec_len (sl1->rewrite));
1152 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1153 sl2->rewrite, vec_len (sl2->rewrite));
1154 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1155 sl3->rewrite, vec_len (sl3->rewrite));
1157 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1158 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1159 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1160 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1162 ip0 = vlib_buffer_get_current (b0);
1163 ip1 = vlib_buffer_get_current (b1);
1164 ip2 = vlib_buffer_get_current (b2);
1165 ip3 = vlib_buffer_get_current (b3);
1167 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1168 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1169 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1170 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1172 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1174 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1176 sr_policy_rewrite_trace_t *tr =
1177 vlib_add_trace (vm, node, b0, sizeof (*tr));
1178 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1179 sizeof (tr->src.as_u8));
1180 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1181 sizeof (tr->dst.as_u8));
1184 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1186 sr_policy_rewrite_trace_t *tr =
1187 vlib_add_trace (vm, node, b1, sizeof (*tr));
1188 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1189 sizeof (tr->src.as_u8));
1190 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1191 sizeof (tr->dst.as_u8));
1194 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1196 sr_policy_rewrite_trace_t *tr =
1197 vlib_add_trace (vm, node, b2, sizeof (*tr));
1198 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1199 sizeof (tr->src.as_u8));
1200 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1201 sizeof (tr->dst.as_u8));
1204 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1206 sr_policy_rewrite_trace_t *tr =
1207 vlib_add_trace (vm, node, b3, sizeof (*tr));
1208 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1209 sizeof (tr->src.as_u8));
1210 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1211 sizeof (tr->dst.as_u8));
1216 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1217 n_left_to_next, bi0, bi1, bi2, bi3,
1218 next0, next1, next2, next3);
1221 /* Single loop for potentially the last three packets */
1222 while (n_left_from > 0 && n_left_to_next > 0)
1226 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1228 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1235 n_left_to_next -= 1;
1236 b0 = vlib_get_buffer (vm, bi0);
1239 pool_elt_at_index (sm->sid_lists,
1240 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1241 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1242 vec_len (sl0->rewrite));
1244 ip0_encap = vlib_buffer_get_current (b0);
1246 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1247 sl0->rewrite, vec_len (sl0->rewrite));
1248 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1250 ip0 = vlib_buffer_get_current (b0);
1252 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1254 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1255 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1257 sr_policy_rewrite_trace_t *tr =
1258 vlib_add_trace (vm, node, b0, sizeof (*tr));
1259 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1260 sizeof (tr->src.as_u8));
1261 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1262 sizeof (tr->dst.as_u8));
1266 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1267 n_left_to_next, bi0, next0);
1270 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1273 /* Update counters */
1274 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1275 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1277 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1278 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1281 return from_frame->n_vectors;
1285 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1286 .function = sr_policy_rewrite_encaps,
1287 .name = "sr-pl-rewrite-encaps",
1288 .vector_size = sizeof (u32),
1289 .format_trace = format_sr_policy_rewrite_trace,
1290 .type = VLIB_NODE_TYPE_INTERNAL,
1291 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1292 .error_strings = sr_policy_rewrite_error_strings,
1293 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1295 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1296 foreach_sr_policy_rewrite_next
1303 * @brief IPv4 encapsulation processing as per RFC2473
1305 static_always_inline void
1306 encaps_processing_v4 (vlib_node_runtime_t * node,
1308 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1311 ip6_sr_header_t *sr0;
1315 /* Inner IPv4: Decrement TTL & update checksum */
1316 ip0_encap->ttl -= 1;
1317 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1318 checksum0 += checksum0 >= 0xffff;
1319 ip0_encap->checksum = checksum0;
1321 /* Outer IPv6: Update length, FL, proto */
1322 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1323 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1324 ip0->ip_version_traffic_class_and_flow_label =
1325 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1326 ((ip0_encap->tos & 0xFF) << 20));
1327 sr0 = (void *) (ip0 + 1);
1328 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1332 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1335 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1336 vlib_frame_t * from_frame)
1338 ip6_sr_main_t *sm = &sr_main;
1339 u32 n_left_from, next_index, *from, *to_next;
1341 from = vlib_frame_vector_args (from_frame);
1342 n_left_from = from_frame->n_vectors;
1344 next_index = node->cached_next_index;
1346 int encap_pkts = 0, bsid_pkts = 0;
1348 while (n_left_from > 0)
1352 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1355 while (n_left_from >= 8 && n_left_to_next >= 4)
1357 u32 bi0, bi1, bi2, bi3;
1358 vlib_buffer_t *b0, *b1, *b2, *b3;
1359 u32 next0, next1, next2, next3;
1360 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1361 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1362 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1363 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1365 /* Prefetch next iteration. */
1367 vlib_buffer_t *p4, *p5, *p6, *p7;
1369 p4 = vlib_get_buffer (vm, from[4]);
1370 p5 = vlib_get_buffer (vm, from[5]);
1371 p6 = vlib_get_buffer (vm, from[6]);
1372 p7 = vlib_get_buffer (vm, from[7]);
1374 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1375 vlib_prefetch_buffer_header (p4, LOAD);
1376 vlib_prefetch_buffer_header (p5, LOAD);
1377 vlib_prefetch_buffer_header (p6, LOAD);
1378 vlib_prefetch_buffer_header (p7, LOAD);
1380 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1381 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1382 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1383 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1386 to_next[0] = bi0 = from[0];
1387 to_next[1] = bi1 = from[1];
1388 to_next[2] = bi2 = from[2];
1389 to_next[3] = bi3 = from[3];
1393 n_left_to_next -= 4;
1395 b0 = vlib_get_buffer (vm, bi0);
1396 b1 = vlib_get_buffer (vm, bi1);
1397 b2 = vlib_get_buffer (vm, bi2);
1398 b3 = vlib_get_buffer (vm, bi3);
1401 pool_elt_at_index (sm->sid_lists,
1402 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1404 pool_elt_at_index (sm->sid_lists,
1405 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1407 pool_elt_at_index (sm->sid_lists,
1408 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1410 pool_elt_at_index (sm->sid_lists,
1411 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1412 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1413 vec_len (sl0->rewrite));
1414 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1415 vec_len (sl1->rewrite));
1416 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1417 vec_len (sl2->rewrite));
1418 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1419 vec_len (sl3->rewrite));
1421 ip0_encap = vlib_buffer_get_current (b0);
1422 ip1_encap = vlib_buffer_get_current (b1);
1423 ip2_encap = vlib_buffer_get_current (b2);
1424 ip3_encap = vlib_buffer_get_current (b3);
1426 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1427 sl0->rewrite, vec_len (sl0->rewrite));
1428 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1429 sl1->rewrite, vec_len (sl1->rewrite));
1430 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1431 sl2->rewrite, vec_len (sl2->rewrite));
1432 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1433 sl3->rewrite, vec_len (sl3->rewrite));
1435 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1436 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1437 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1438 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1440 ip0 = vlib_buffer_get_current (b0);
1441 ip1 = vlib_buffer_get_current (b1);
1442 ip2 = vlib_buffer_get_current (b2);
1443 ip3 = vlib_buffer_get_current (b3);
1445 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1446 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1447 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1448 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1450 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1452 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1454 sr_policy_rewrite_trace_t *tr =
1455 vlib_add_trace (vm, node, b0, sizeof (*tr));
1456 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1457 sizeof (tr->src.as_u8));
1458 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1459 sizeof (tr->dst.as_u8));
1462 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1464 sr_policy_rewrite_trace_t *tr =
1465 vlib_add_trace (vm, node, b1, sizeof (*tr));
1466 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1467 sizeof (tr->src.as_u8));
1468 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1469 sizeof (tr->dst.as_u8));
1472 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b2, sizeof (*tr));
1476 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
1482 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1484 sr_policy_rewrite_trace_t *tr =
1485 vlib_add_trace (vm, node, b3, sizeof (*tr));
1486 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1487 sizeof (tr->src.as_u8));
1488 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1489 sizeof (tr->dst.as_u8));
1494 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1495 n_left_to_next, bi0, bi1, bi2, bi3,
1496 next0, next1, next2, next3);
1499 /* Single loop for potentially the last three packets */
1500 while (n_left_from > 0 && n_left_to_next > 0)
1504 ip6_header_t *ip0 = 0;
1505 ip4_header_t *ip0_encap = 0;
1507 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1514 n_left_to_next -= 1;
1515 b0 = vlib_get_buffer (vm, bi0);
1518 pool_elt_at_index (sm->sid_lists,
1519 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1520 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1521 vec_len (sl0->rewrite));
1523 ip0_encap = vlib_buffer_get_current (b0);
1525 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1526 sl0->rewrite, vec_len (sl0->rewrite));
1527 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1529 ip0 = vlib_buffer_get_current (b0);
1531 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1533 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1534 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1536 sr_policy_rewrite_trace_t *tr =
1537 vlib_add_trace (vm, node, b0, sizeof (*tr));
1538 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1539 sizeof (tr->src.as_u8));
1540 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1541 sizeof (tr->dst.as_u8));
1545 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1546 n_left_to_next, bi0, next0);
1549 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1552 /* Update counters */
1553 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1554 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1556 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1557 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1560 return from_frame->n_vectors;
1564 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1565 .function = sr_policy_rewrite_encaps_v4,
1566 .name = "sr-pl-rewrite-encaps-v4",
1567 .vector_size = sizeof (u32),
1568 .format_trace = format_sr_policy_rewrite_trace,
1569 .type = VLIB_NODE_TYPE_INTERNAL,
1570 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1571 .error_strings = sr_policy_rewrite_error_strings,
1572 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1574 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1575 foreach_sr_policy_rewrite_next
1582 ip_flow_hash (void *data)
1584 ip4_header_t *iph = (ip4_header_t *) data;
1586 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1587 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1589 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1595 return (*((u64 *) m) & 0xffffffffffff);
1599 l2_flow_hash (vlib_buffer_t * b0)
1601 ethernet_header_t *eh;
1603 uword is_ip, eh_size;
1606 eh = vlib_buffer_get_current (b0);
1607 eh_type = clib_net_to_host_u16 (eh->type);
1608 eh_size = ethernet_buffer_header_size (b0);
1610 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1612 /* since we have 2 cache lines, use them */
1614 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1618 b = mac_to_u64 ((u8 *) eh->dst_address);
1619 c = mac_to_u64 ((u8 *) eh->src_address);
1620 hash_mix64 (a, b, c);
1626 * @brief Graph node for applying a SR policy into a L2 frame
1629 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1630 vlib_frame_t * from_frame)
1632 ip6_sr_main_t *sm = &sr_main;
1633 u32 n_left_from, next_index, *from, *to_next;
1635 from = vlib_frame_vector_args (from_frame);
1636 n_left_from = from_frame->n_vectors;
1638 next_index = node->cached_next_index;
1640 int encap_pkts = 0, bsid_pkts = 0;
1642 while (n_left_from > 0)
1646 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1649 while (n_left_from >= 8 && n_left_to_next >= 4)
1651 u32 bi0, bi1, bi2, bi3;
1652 vlib_buffer_t *b0, *b1, *b2, *b3;
1653 u32 next0, next1, next2, next3;
1654 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1655 ethernet_header_t *en0, *en1, *en2, *en3;
1656 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1657 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1658 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1659 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1661 /* Prefetch next iteration. */
1663 vlib_buffer_t *p4, *p5, *p6, *p7;
1665 p4 = vlib_get_buffer (vm, from[4]);
1666 p5 = vlib_get_buffer (vm, from[5]);
1667 p6 = vlib_get_buffer (vm, from[6]);
1668 p7 = vlib_get_buffer (vm, from[7]);
1670 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1671 vlib_prefetch_buffer_header (p4, LOAD);
1672 vlib_prefetch_buffer_header (p5, LOAD);
1673 vlib_prefetch_buffer_header (p6, LOAD);
1674 vlib_prefetch_buffer_header (p7, LOAD);
1676 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1677 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1678 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1679 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1682 to_next[0] = bi0 = from[0];
1683 to_next[1] = bi1 = from[1];
1684 to_next[2] = bi2 = from[2];
1685 to_next[3] = bi3 = from[3];
1689 n_left_to_next -= 4;
1691 b0 = vlib_get_buffer (vm, bi0);
1692 b1 = vlib_get_buffer (vm, bi1);
1693 b2 = vlib_get_buffer (vm, bi2);
1694 b3 = vlib_get_buffer (vm, bi3);
1696 sp0 = pool_elt_at_index (sm->sr_policies,
1697 sm->sw_iface_sr_policies[vnet_buffer
1701 sp1 = pool_elt_at_index (sm->sr_policies,
1702 sm->sw_iface_sr_policies[vnet_buffer
1706 sp2 = pool_elt_at_index (sm->sr_policies,
1707 sm->sw_iface_sr_policies[vnet_buffer
1711 sp3 = pool_elt_at_index (sm->sr_policies,
1712 sm->sw_iface_sr_policies[vnet_buffer
1716 if (vec_len (sp0->segments_lists) == 1)
1717 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1720 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1721 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1722 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1723 (vec_len (sp0->segments_lists) - 1))];
1726 if (vec_len (sp1->segments_lists) == 1)
1727 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1730 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1731 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1732 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1733 (vec_len (sp1->segments_lists) - 1))];
1736 if (vec_len (sp2->segments_lists) == 1)
1737 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1740 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1741 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1742 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1743 (vec_len (sp2->segments_lists) - 1))];
1746 if (vec_len (sp3->segments_lists) == 1)
1747 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1750 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1751 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1752 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1753 (vec_len (sp3->segments_lists) - 1))];
1757 pool_elt_at_index (sm->sid_lists,
1758 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1760 pool_elt_at_index (sm->sid_lists,
1761 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1763 pool_elt_at_index (sm->sid_lists,
1764 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1766 pool_elt_at_index (sm->sid_lists,
1767 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1769 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1770 vec_len (sl0->rewrite));
1771 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1772 vec_len (sl1->rewrite));
1773 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1774 vec_len (sl2->rewrite));
1775 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1776 vec_len (sl3->rewrite));
1778 en0 = vlib_buffer_get_current (b0);
1779 en1 = vlib_buffer_get_current (b1);
1780 en2 = vlib_buffer_get_current (b2);
1781 en3 = vlib_buffer_get_current (b3);
1783 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1784 vec_len (sl0->rewrite));
1785 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1786 vec_len (sl1->rewrite));
1787 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1788 vec_len (sl2->rewrite));
1789 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1790 vec_len (sl3->rewrite));
1792 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1793 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1794 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1795 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1797 ip0 = vlib_buffer_get_current (b0);
1798 ip1 = vlib_buffer_get_current (b1);
1799 ip2 = vlib_buffer_get_current (b2);
1800 ip3 = vlib_buffer_get_current (b3);
1802 ip0->payload_length =
1803 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1804 ip1->payload_length =
1805 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1806 ip2->payload_length =
1807 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1808 ip3->payload_length =
1809 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1811 sr0 = (void *) (ip0 + 1);
1812 sr1 = (void *) (ip1 + 1);
1813 sr2 = (void *) (ip2 + 1);
1814 sr3 = (void *) (ip3 + 1);
1816 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1817 IP_PROTOCOL_IP6_NONXT;
1819 /* Which Traffic class and flow label do I set ? */
1820 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1822 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1824 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1826 sr_policy_rewrite_trace_t *tr =
1827 vlib_add_trace (vm, node, b0, sizeof (*tr));
1828 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1829 sizeof (tr->src.as_u8));
1830 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1831 sizeof (tr->dst.as_u8));
1834 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1836 sr_policy_rewrite_trace_t *tr =
1837 vlib_add_trace (vm, node, b1, sizeof (*tr));
1838 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1839 sizeof (tr->src.as_u8));
1840 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1841 sizeof (tr->dst.as_u8));
1844 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1846 sr_policy_rewrite_trace_t *tr =
1847 vlib_add_trace (vm, node, b2, sizeof (*tr));
1848 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1849 sizeof (tr->src.as_u8));
1850 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1851 sizeof (tr->dst.as_u8));
1854 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1856 sr_policy_rewrite_trace_t *tr =
1857 vlib_add_trace (vm, node, b3, sizeof (*tr));
1858 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1859 sizeof (tr->src.as_u8));
1860 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1861 sizeof (tr->dst.as_u8));
1866 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1867 n_left_to_next, bi0, bi1, bi2, bi3,
1868 next0, next1, next2, next3);
1871 /* Single loop for potentially the last three packets */
1872 while (n_left_from > 0 && n_left_to_next > 0)
1876 ip6_header_t *ip0 = 0;
1877 ip6_sr_header_t *sr0;
1878 ethernet_header_t *en0;
1879 ip6_sr_policy_t *sp0;
1881 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1888 n_left_to_next -= 1;
1889 b0 = vlib_get_buffer (vm, bi0);
1891 /* Find the SR policy */
1892 sp0 = pool_elt_at_index (sm->sr_policies,
1893 sm->sw_iface_sr_policies[vnet_buffer
1897 /* In case there is more than one SL, LB among them */
1898 if (vec_len (sp0->segments_lists) == 1)
1899 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1902 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1903 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1904 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1905 (vec_len (sp0->segments_lists) - 1))];
1908 pool_elt_at_index (sm->sid_lists,
1909 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1910 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1911 vec_len (sl0->rewrite));
1913 en0 = vlib_buffer_get_current (b0);
1915 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1916 vec_len (sl0->rewrite));
1918 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1920 ip0 = vlib_buffer_get_current (b0);
1922 ip0->payload_length =
1923 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1925 sr0 = (void *) (ip0 + 1);
1926 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1928 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1929 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1931 sr_policy_rewrite_trace_t *tr =
1932 vlib_add_trace (vm, node, b0, sizeof (*tr));
1933 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1934 sizeof (tr->src.as_u8));
1935 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1936 sizeof (tr->dst.as_u8));
1940 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1941 n_left_to_next, bi0, next0);
1944 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1947 /* Update counters */
1948 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1949 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1951 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1952 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1955 return from_frame->n_vectors;
1959 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1960 .function = sr_policy_rewrite_encaps_l2,
1961 .name = "sr-pl-rewrite-encaps-l2",
1962 .vector_size = sizeof (u32),
1963 .format_trace = format_sr_policy_rewrite_trace,
1964 .type = VLIB_NODE_TYPE_INTERNAL,
1965 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1966 .error_strings = sr_policy_rewrite_error_strings,
1967 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1969 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1970 foreach_sr_policy_rewrite_next
1977 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1980 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1981 vlib_frame_t * from_frame)
1983 ip6_sr_main_t *sm = &sr_main;
1984 u32 n_left_from, next_index, *from, *to_next;
1986 from = vlib_frame_vector_args (from_frame);
1987 n_left_from = from_frame->n_vectors;
1989 next_index = node->cached_next_index;
1991 int insert_pkts = 0, bsid_pkts = 0;
1993 while (n_left_from > 0)
1997 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2000 while (n_left_from >= 8 && n_left_to_next >= 4)
2002 u32 bi0, bi1, bi2, bi3;
2003 vlib_buffer_t *b0, *b1, *b2, *b3;
2004 u32 next0, next1, next2, next3;
2005 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2006 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2007 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2008 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2009 u16 new_l0, new_l1, new_l2, new_l3;
2011 /* Prefetch next iteration. */
2013 vlib_buffer_t *p4, *p5, *p6, *p7;
2015 p4 = vlib_get_buffer (vm, from[4]);
2016 p5 = vlib_get_buffer (vm, from[5]);
2017 p6 = vlib_get_buffer (vm, from[6]);
2018 p7 = vlib_get_buffer (vm, from[7]);
2020 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2021 vlib_prefetch_buffer_header (p4, LOAD);
2022 vlib_prefetch_buffer_header (p5, LOAD);
2023 vlib_prefetch_buffer_header (p6, LOAD);
2024 vlib_prefetch_buffer_header (p7, LOAD);
2026 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2027 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2028 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2029 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2032 to_next[0] = bi0 = from[0];
2033 to_next[1] = bi1 = from[1];
2034 to_next[2] = bi2 = from[2];
2035 to_next[3] = bi3 = from[3];
2039 n_left_to_next -= 4;
2041 b0 = vlib_get_buffer (vm, bi0);
2042 b1 = vlib_get_buffer (vm, bi1);
2043 b2 = vlib_get_buffer (vm, bi2);
2044 b3 = vlib_get_buffer (vm, bi3);
2047 pool_elt_at_index (sm->sid_lists,
2048 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2050 pool_elt_at_index (sm->sid_lists,
2051 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2053 pool_elt_at_index (sm->sid_lists,
2054 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2056 pool_elt_at_index (sm->sid_lists,
2057 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2058 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2059 vec_len (sl0->rewrite));
2060 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2061 vec_len (sl1->rewrite));
2062 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2063 vec_len (sl2->rewrite));
2064 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2065 vec_len (sl3->rewrite));
2067 ip0 = vlib_buffer_get_current (b0);
2068 ip1 = vlib_buffer_get_current (b1);
2069 ip2 = vlib_buffer_get_current (b2);
2070 ip3 = vlib_buffer_get_current (b3);
2072 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2074 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2075 ip6_ext_header_len (ip0 + 1));
2077 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2079 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2081 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2082 ip6_ext_header_len (ip1 + 1));
2084 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2086 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2088 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2089 ip6_ext_header_len (ip2 + 1));
2091 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2093 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2095 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2096 ip6_ext_header_len (ip3 + 1));
2098 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2100 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2101 (void *) sr0 - (void *) ip0);
2102 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2103 (void *) sr1 - (void *) ip1);
2104 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2105 (void *) sr2 - (void *) ip2);
2106 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2107 (void *) sr3 - (void *) ip3);
2109 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2110 vec_len (sl0->rewrite));
2111 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2112 vec_len (sl1->rewrite));
2113 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2114 vec_len (sl2->rewrite));
2115 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2116 vec_len (sl3->rewrite));
2118 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2119 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2120 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2121 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2123 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2124 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2125 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2126 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2128 ip0->hop_limit -= 1;
2129 ip1->hop_limit -= 1;
2130 ip2->hop_limit -= 1;
2131 ip3->hop_limit -= 1;
2134 clib_net_to_host_u16 (ip0->payload_length) +
2135 vec_len (sl0->rewrite);
2137 clib_net_to_host_u16 (ip1->payload_length) +
2138 vec_len (sl1->rewrite);
2140 clib_net_to_host_u16 (ip2->payload_length) +
2141 vec_len (sl2->rewrite);
2143 clib_net_to_host_u16 (ip3->payload_length) +
2144 vec_len (sl3->rewrite);
2146 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2147 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2148 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2149 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2151 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2152 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2153 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2154 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2156 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2157 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2158 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2159 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2160 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2161 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2162 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2163 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2165 ip0->dst_address.as_u64[0] =
2166 (sr0->segments + sr0->segments_left)->as_u64[0];
2167 ip0->dst_address.as_u64[1] =
2168 (sr0->segments + sr0->segments_left)->as_u64[1];
2169 ip1->dst_address.as_u64[0] =
2170 (sr1->segments + sr1->segments_left)->as_u64[0];
2171 ip1->dst_address.as_u64[1] =
2172 (sr1->segments + sr1->segments_left)->as_u64[1];
2173 ip2->dst_address.as_u64[0] =
2174 (sr2->segments + sr2->segments_left)->as_u64[0];
2175 ip2->dst_address.as_u64[1] =
2176 (sr2->segments + sr2->segments_left)->as_u64[1];
2177 ip3->dst_address.as_u64[0] =
2178 (sr3->segments + sr3->segments_left)->as_u64[0];
2179 ip3->dst_address.as_u64[1] =
2180 (sr3->segments + sr3->segments_left)->as_u64[1];
2182 ip6_ext_header_t *ip_ext;
2183 if (ip0 + 1 == (void *) sr0)
2185 sr0->protocol = ip0->protocol;
2186 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2190 ip_ext = (void *) (ip0 + 1);
2191 sr0->protocol = ip_ext->next_hdr;
2192 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2195 if (ip1 + 1 == (void *) sr1)
2197 sr1->protocol = ip1->protocol;
2198 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2202 ip_ext = (void *) (ip2 + 1);
2203 sr2->protocol = ip_ext->next_hdr;
2204 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2207 if (ip2 + 1 == (void *) sr2)
2209 sr2->protocol = ip2->protocol;
2210 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2214 ip_ext = (void *) (ip2 + 1);
2215 sr2->protocol = ip_ext->next_hdr;
2216 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2219 if (ip3 + 1 == (void *) sr3)
2221 sr3->protocol = ip3->protocol;
2222 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2226 ip_ext = (void *) (ip3 + 1);
2227 sr3->protocol = ip_ext->next_hdr;
2228 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2233 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2235 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2237 sr_policy_rewrite_trace_t *tr =
2238 vlib_add_trace (vm, node, b0, sizeof (*tr));
2239 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2240 sizeof (tr->src.as_u8));
2241 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2242 sizeof (tr->dst.as_u8));
2245 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2247 sr_policy_rewrite_trace_t *tr =
2248 vlib_add_trace (vm, node, b1, sizeof (*tr));
2249 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2250 sizeof (tr->src.as_u8));
2251 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2252 sizeof (tr->dst.as_u8));
2255 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2257 sr_policy_rewrite_trace_t *tr =
2258 vlib_add_trace (vm, node, b2, sizeof (*tr));
2259 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2260 sizeof (tr->src.as_u8));
2261 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2262 sizeof (tr->dst.as_u8));
2265 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2267 sr_policy_rewrite_trace_t *tr =
2268 vlib_add_trace (vm, node, b3, sizeof (*tr));
2269 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2270 sizeof (tr->src.as_u8));
2271 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2272 sizeof (tr->dst.as_u8));
2276 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2277 n_left_to_next, bi0, bi1, bi2, bi3,
2278 next0, next1, next2, next3);
2281 /* Single loop for potentially the last three packets */
2282 while (n_left_from > 0 && n_left_to_next > 0)
2286 ip6_header_t *ip0 = 0;
2287 ip6_sr_header_t *sr0 = 0;
2289 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2297 n_left_to_next -= 1;
2299 b0 = vlib_get_buffer (vm, bi0);
2301 pool_elt_at_index (sm->sid_lists,
2302 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2303 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2304 vec_len (sl0->rewrite));
2306 ip0 = vlib_buffer_get_current (b0);
2308 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2310 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2311 ip6_ext_header_len (ip0 + 1));
2313 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2315 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2316 (void *) sr0 - (void *) ip0);
2317 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2318 vec_len (sl0->rewrite));
2320 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2322 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2323 ip0->hop_limit -= 1;
2325 clib_net_to_host_u16 (ip0->payload_length) +
2326 vec_len (sl0->rewrite);
2327 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2329 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2330 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2331 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2333 ip0->dst_address.as_u64[0] =
2334 (sr0->segments + sr0->segments_left)->as_u64[0];
2335 ip0->dst_address.as_u64[1] =
2336 (sr0->segments + sr0->segments_left)->as_u64[1];
2338 if (ip0 + 1 == (void *) sr0)
2340 sr0->protocol = ip0->protocol;
2341 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2345 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2346 sr0->protocol = ip_ext->next_hdr;
2347 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2350 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2351 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2353 sr_policy_rewrite_trace_t *tr =
2354 vlib_add_trace (vm, node, b0, sizeof (*tr));
2355 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2356 sizeof (tr->src.as_u8));
2357 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2358 sizeof (tr->dst.as_u8));
2363 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2364 n_left_to_next, bi0, next0);
2367 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2370 /* Update counters */
2371 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2372 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2374 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2375 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2377 return from_frame->n_vectors;
2381 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2382 .function = sr_policy_rewrite_insert,
2383 .name = "sr-pl-rewrite-insert",
2384 .vector_size = sizeof (u32),
2385 .format_trace = format_sr_policy_rewrite_trace,
2386 .type = VLIB_NODE_TYPE_INTERNAL,
2387 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2388 .error_strings = sr_policy_rewrite_error_strings,
2389 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2391 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2392 foreach_sr_policy_rewrite_next
2399 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2402 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2403 vlib_frame_t * from_frame)
2405 ip6_sr_main_t *sm = &sr_main;
2406 u32 n_left_from, next_index, *from, *to_next;
2408 from = vlib_frame_vector_args (from_frame);
2409 n_left_from = from_frame->n_vectors;
2411 next_index = node->cached_next_index;
2413 int insert_pkts = 0, bsid_pkts = 0;
2415 while (n_left_from > 0)
2419 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2422 while (n_left_from >= 8 && n_left_to_next >= 4)
2424 u32 bi0, bi1, bi2, bi3;
2425 vlib_buffer_t *b0, *b1, *b2, *b3;
2426 u32 next0, next1, next2, next3;
2427 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2428 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2429 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2430 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2431 u16 new_l0, new_l1, new_l2, new_l3;
2433 /* Prefetch next iteration. */
2435 vlib_buffer_t *p4, *p5, *p6, *p7;
2437 p4 = vlib_get_buffer (vm, from[4]);
2438 p5 = vlib_get_buffer (vm, from[5]);
2439 p6 = vlib_get_buffer (vm, from[6]);
2440 p7 = vlib_get_buffer (vm, from[7]);
2442 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2443 vlib_prefetch_buffer_header (p4, LOAD);
2444 vlib_prefetch_buffer_header (p5, LOAD);
2445 vlib_prefetch_buffer_header (p6, LOAD);
2446 vlib_prefetch_buffer_header (p7, LOAD);
2448 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2449 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2450 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2451 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2454 to_next[0] = bi0 = from[0];
2455 to_next[1] = bi1 = from[1];
2456 to_next[2] = bi2 = from[2];
2457 to_next[3] = bi3 = from[3];
2461 n_left_to_next -= 4;
2463 b0 = vlib_get_buffer (vm, bi0);
2464 b1 = vlib_get_buffer (vm, bi1);
2465 b2 = vlib_get_buffer (vm, bi2);
2466 b3 = vlib_get_buffer (vm, bi3);
2469 pool_elt_at_index (sm->sid_lists,
2470 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2472 pool_elt_at_index (sm->sid_lists,
2473 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2475 pool_elt_at_index (sm->sid_lists,
2476 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2478 pool_elt_at_index (sm->sid_lists,
2479 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2480 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2481 vec_len (sl0->rewrite_bsid));
2482 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2483 vec_len (sl1->rewrite_bsid));
2484 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2485 vec_len (sl2->rewrite_bsid));
2486 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2487 vec_len (sl3->rewrite_bsid));
2489 ip0 = vlib_buffer_get_current (b0);
2490 ip1 = vlib_buffer_get_current (b1);
2491 ip2 = vlib_buffer_get_current (b2);
2492 ip3 = vlib_buffer_get_current (b3);
2494 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2496 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2497 ip6_ext_header_len (ip0 + 1));
2499 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2501 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2503 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2504 ip6_ext_header_len (ip1 + 1));
2506 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2508 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2510 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2511 ip6_ext_header_len (ip2 + 1));
2513 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2515 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2517 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2518 ip6_ext_header_len (ip3 + 1));
2520 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2522 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2523 (void *) sr0 - (void *) ip0);
2524 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2525 (void *) sr1 - (void *) ip1);
2526 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2527 (void *) sr2 - (void *) ip2);
2528 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2529 (void *) sr3 - (void *) ip3);
2531 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2532 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2533 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2534 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2535 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2536 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2537 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2538 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2540 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2541 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2542 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2543 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2545 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2546 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2547 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2548 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2550 ip0->hop_limit -= 1;
2551 ip1->hop_limit -= 1;
2552 ip2->hop_limit -= 1;
2553 ip3->hop_limit -= 1;
2556 clib_net_to_host_u16 (ip0->payload_length) +
2557 vec_len (sl0->rewrite_bsid);
2559 clib_net_to_host_u16 (ip1->payload_length) +
2560 vec_len (sl1->rewrite_bsid);
2562 clib_net_to_host_u16 (ip2->payload_length) +
2563 vec_len (sl2->rewrite_bsid);
2565 clib_net_to_host_u16 (ip3->payload_length) +
2566 vec_len (sl3->rewrite_bsid);
2568 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2569 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2570 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2571 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2573 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2574 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2575 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2576 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2578 ip0->dst_address.as_u64[0] =
2579 (sr0->segments + sr0->segments_left)->as_u64[0];
2580 ip0->dst_address.as_u64[1] =
2581 (sr0->segments + sr0->segments_left)->as_u64[1];
2582 ip1->dst_address.as_u64[0] =
2583 (sr1->segments + sr1->segments_left)->as_u64[0];
2584 ip1->dst_address.as_u64[1] =
2585 (sr1->segments + sr1->segments_left)->as_u64[1];
2586 ip2->dst_address.as_u64[0] =
2587 (sr2->segments + sr2->segments_left)->as_u64[0];
2588 ip2->dst_address.as_u64[1] =
2589 (sr2->segments + sr2->segments_left)->as_u64[1];
2590 ip3->dst_address.as_u64[0] =
2591 (sr3->segments + sr3->segments_left)->as_u64[0];
2592 ip3->dst_address.as_u64[1] =
2593 (sr3->segments + sr3->segments_left)->as_u64[1];
2595 ip6_ext_header_t *ip_ext;
2596 if (ip0 + 1 == (void *) sr0)
2598 sr0->protocol = ip0->protocol;
2599 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2603 ip_ext = (void *) (ip0 + 1);
2604 sr0->protocol = ip_ext->next_hdr;
2605 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2608 if (ip1 + 1 == (void *) sr1)
2610 sr1->protocol = ip1->protocol;
2611 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2615 ip_ext = (void *) (ip2 + 1);
2616 sr2->protocol = ip_ext->next_hdr;
2617 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2620 if (ip2 + 1 == (void *) sr2)
2622 sr2->protocol = ip2->protocol;
2623 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2627 ip_ext = (void *) (ip2 + 1);
2628 sr2->protocol = ip_ext->next_hdr;
2629 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2632 if (ip3 + 1 == (void *) sr3)
2634 sr3->protocol = ip3->protocol;
2635 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2639 ip_ext = (void *) (ip3 + 1);
2640 sr3->protocol = ip_ext->next_hdr;
2641 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2646 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2648 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2650 sr_policy_rewrite_trace_t *tr =
2651 vlib_add_trace (vm, node, b0, sizeof (*tr));
2652 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2653 sizeof (tr->src.as_u8));
2654 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2655 sizeof (tr->dst.as_u8));
2658 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2660 sr_policy_rewrite_trace_t *tr =
2661 vlib_add_trace (vm, node, b1, sizeof (*tr));
2662 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2663 sizeof (tr->src.as_u8));
2664 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2665 sizeof (tr->dst.as_u8));
2668 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2670 sr_policy_rewrite_trace_t *tr =
2671 vlib_add_trace (vm, node, b2, sizeof (*tr));
2672 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2673 sizeof (tr->src.as_u8));
2674 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2675 sizeof (tr->dst.as_u8));
2678 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2680 sr_policy_rewrite_trace_t *tr =
2681 vlib_add_trace (vm, node, b3, sizeof (*tr));
2682 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2683 sizeof (tr->src.as_u8));
2684 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2685 sizeof (tr->dst.as_u8));
2689 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2690 n_left_to_next, bi0, bi1, bi2, bi3,
2691 next0, next1, next2, next3);
2694 /* Single loop for potentially the last three packets */
2695 while (n_left_from > 0 && n_left_to_next > 0)
2699 ip6_header_t *ip0 = 0;
2700 ip6_sr_header_t *sr0 = 0;
2702 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2710 n_left_to_next -= 1;
2712 b0 = vlib_get_buffer (vm, bi0);
2714 pool_elt_at_index (sm->sid_lists,
2715 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2716 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2717 vec_len (sl0->rewrite_bsid));
2719 ip0 = vlib_buffer_get_current (b0);
2721 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2723 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2724 ip6_ext_header_len (ip0 + 1));
2726 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2728 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2729 (void *) sr0 - (void *) ip0);
2730 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2731 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2733 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2735 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2736 ip0->hop_limit -= 1;
2738 clib_net_to_host_u16 (ip0->payload_length) +
2739 vec_len (sl0->rewrite_bsid);
2740 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2742 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2744 ip0->dst_address.as_u64[0] =
2745 (sr0->segments + sr0->segments_left)->as_u64[0];
2746 ip0->dst_address.as_u64[1] =
2747 (sr0->segments + sr0->segments_left)->as_u64[1];
2749 if (ip0 + 1 == (void *) sr0)
2751 sr0->protocol = ip0->protocol;
2752 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2756 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2757 sr0->protocol = ip_ext->next_hdr;
2758 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2761 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2762 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2764 sr_policy_rewrite_trace_t *tr =
2765 vlib_add_trace (vm, node, b0, sizeof (*tr));
2766 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2767 sizeof (tr->src.as_u8));
2768 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2769 sizeof (tr->dst.as_u8));
2774 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2775 n_left_to_next, bi0, next0);
2778 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2781 /* Update counters */
2782 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2783 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2785 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2786 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2788 return from_frame->n_vectors;
2792 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2793 .function = sr_policy_rewrite_b_insert,
2794 .name = "sr-pl-rewrite-b-insert",
2795 .vector_size = sizeof (u32),
2796 .format_trace = format_sr_policy_rewrite_trace,
2797 .type = VLIB_NODE_TYPE_INTERNAL,
2798 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2799 .error_strings = sr_policy_rewrite_error_strings,
2800 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2802 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2803 foreach_sr_policy_rewrite_next
2810 * @brief Function BSID encapsulation
2812 static_always_inline void
2813 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2816 ip6_sr_header_t * sr0, u32 * next0)
2818 ip6_address_t *new_dst0;
2820 if (PREDICT_FALSE (!sr0))
2821 goto error_bsid_encaps;
2823 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2825 if (PREDICT_TRUE (sr0->segments_left != 0))
2827 sr0->segments_left -= 1;
2828 new_dst0 = (ip6_address_t *) (sr0->segments);
2829 new_dst0 += sr0->segments_left;
2830 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2831 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2837 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2838 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2842 * @brief Graph node for applying a SR policy BSID - Encapsulation
2845 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2846 vlib_frame_t * from_frame)
2848 ip6_sr_main_t *sm = &sr_main;
2849 u32 n_left_from, next_index, *from, *to_next;
2851 from = vlib_frame_vector_args (from_frame);
2852 n_left_from = from_frame->n_vectors;
2854 next_index = node->cached_next_index;
2856 int encap_pkts = 0, bsid_pkts = 0;
2858 while (n_left_from > 0)
2862 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2865 while (n_left_from >= 8 && n_left_to_next >= 4)
2867 u32 bi0, bi1, bi2, bi3;
2868 vlib_buffer_t *b0, *b1, *b2, *b3;
2869 u32 next0, next1, next2, next3;
2870 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2871 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2872 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2873 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2874 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2875 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2877 /* Prefetch next iteration. */
2879 vlib_buffer_t *p4, *p5, *p6, *p7;
2881 p4 = vlib_get_buffer (vm, from[4]);
2882 p5 = vlib_get_buffer (vm, from[5]);
2883 p6 = vlib_get_buffer (vm, from[6]);
2884 p7 = vlib_get_buffer (vm, from[7]);
2886 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2887 vlib_prefetch_buffer_header (p4, LOAD);
2888 vlib_prefetch_buffer_header (p5, LOAD);
2889 vlib_prefetch_buffer_header (p6, LOAD);
2890 vlib_prefetch_buffer_header (p7, LOAD);
2892 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2893 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2894 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2895 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2898 to_next[0] = bi0 = from[0];
2899 to_next[1] = bi1 = from[1];
2900 to_next[2] = bi2 = from[2];
2901 to_next[3] = bi3 = from[3];
2905 n_left_to_next -= 4;
2907 b0 = vlib_get_buffer (vm, bi0);
2908 b1 = vlib_get_buffer (vm, bi1);
2909 b2 = vlib_get_buffer (vm, bi2);
2910 b3 = vlib_get_buffer (vm, bi3);
2913 pool_elt_at_index (sm->sid_lists,
2914 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2916 pool_elt_at_index (sm->sid_lists,
2917 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2919 pool_elt_at_index (sm->sid_lists,
2920 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2922 pool_elt_at_index (sm->sid_lists,
2923 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2924 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2925 vec_len (sl0->rewrite));
2926 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2927 vec_len (sl1->rewrite));
2928 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929 vec_len (sl2->rewrite));
2930 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2931 vec_len (sl3->rewrite));
2933 ip0_encap = vlib_buffer_get_current (b0);
2934 ip1_encap = vlib_buffer_get_current (b1);
2935 ip2_encap = vlib_buffer_get_current (b2);
2936 ip3_encap = vlib_buffer_get_current (b3);
2938 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2939 IP_PROTOCOL_IPV6_ROUTE);
2940 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2941 IP_PROTOCOL_IPV6_ROUTE);
2942 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2943 IP_PROTOCOL_IPV6_ROUTE);
2944 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2945 IP_PROTOCOL_IPV6_ROUTE);
2947 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2948 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2949 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2950 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2952 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2953 sl0->rewrite, vec_len (sl0->rewrite));
2954 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2955 sl1->rewrite, vec_len (sl1->rewrite));
2956 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2957 sl2->rewrite, vec_len (sl2->rewrite));
2958 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2959 sl3->rewrite, vec_len (sl3->rewrite));
2961 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2962 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2963 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2964 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2966 ip0 = vlib_buffer_get_current (b0);
2967 ip1 = vlib_buffer_get_current (b1);
2968 ip2 = vlib_buffer_get_current (b2);
2969 ip3 = vlib_buffer_get_current (b3);
2971 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2972 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2973 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2974 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2976 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2978 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2980 sr_policy_rewrite_trace_t *tr =
2981 vlib_add_trace (vm, node, b0, sizeof (*tr));
2982 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2983 sizeof (tr->src.as_u8));
2984 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2985 sizeof (tr->dst.as_u8));
2988 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2990 sr_policy_rewrite_trace_t *tr =
2991 vlib_add_trace (vm, node, b1, sizeof (*tr));
2992 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2993 sizeof (tr->src.as_u8));
2994 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2995 sizeof (tr->dst.as_u8));
2998 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3000 sr_policy_rewrite_trace_t *tr =
3001 vlib_add_trace (vm, node, b2, sizeof (*tr));
3002 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3003 sizeof (tr->src.as_u8));
3004 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3005 sizeof (tr->dst.as_u8));
3008 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3010 sr_policy_rewrite_trace_t *tr =
3011 vlib_add_trace (vm, node, b3, sizeof (*tr));
3012 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3013 sizeof (tr->src.as_u8));
3014 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3015 sizeof (tr->dst.as_u8));
3020 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3021 n_left_to_next, bi0, bi1, bi2, bi3,
3022 next0, next1, next2, next3);
3025 /* Single loop for potentially the last three packets */
3026 while (n_left_from > 0 && n_left_to_next > 0)
3030 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3031 ip6_ext_header_t *prev0;
3032 ip6_sr_header_t *sr0;
3034 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3041 n_left_to_next -= 1;
3042 b0 = vlib_get_buffer (vm, bi0);
3045 pool_elt_at_index (sm->sid_lists,
3046 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3047 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3048 vec_len (sl0->rewrite));
3050 ip0_encap = vlib_buffer_get_current (b0);
3051 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3052 IP_PROTOCOL_IPV6_ROUTE);
3053 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3055 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3056 sl0->rewrite, vec_len (sl0->rewrite));
3057 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3059 ip0 = vlib_buffer_get_current (b0);
3061 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3063 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3064 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3066 sr_policy_rewrite_trace_t *tr =
3067 vlib_add_trace (vm, node, b0, sizeof (*tr));
3068 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3069 sizeof (tr->src.as_u8));
3070 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3071 sizeof (tr->dst.as_u8));
3075 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3076 n_left_to_next, bi0, next0);
3079 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3082 /* Update counters */
3083 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3084 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3086 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3087 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3090 return from_frame->n_vectors;
3094 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3095 .function = sr_policy_rewrite_b_encaps,
3096 .name = "sr-pl-rewrite-b-encaps",
3097 .vector_size = sizeof (u32),
3098 .format_trace = format_sr_policy_rewrite_trace,
3099 .type = VLIB_NODE_TYPE_INTERNAL,
3100 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3101 .error_strings = sr_policy_rewrite_error_strings,
3102 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3104 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3105 foreach_sr_policy_rewrite_next
3111 /*************************** SR Segment Lists DPOs ****************************/
3113 format_sr_segment_list_dpo (u8 * s, va_list * args)
3115 ip6_sr_main_t *sm = &sr_main;
3116 ip6_address_t *addr;
3119 index_t index = va_arg (*args, index_t);
3120 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3121 s = format (s, "SR: Segment List index:[%d]", index);
3122 s = format (s, "\n\tSegments:");
3124 sl = pool_elt_at_index (sm->sid_lists, index);
3126 s = format (s, "< ");
3127 vec_foreach (addr, sl->segments)
3129 s = format (s, "%U, ", format_ip6_address, addr);
3131 s = format (s, "\b\b > - ");
3132 s = format (s, "Weight: %u", sl->weight);
3137 const static dpo_vft_t sr_policy_rewrite_vft = {
3138 .dv_lock = sr_dpo_lock,
3139 .dv_unlock = sr_dpo_unlock,
3140 .dv_format = format_sr_segment_list_dpo,
3143 const static char *const sr_pr_encaps_ip6_nodes[] = {
3144 "sr-pl-rewrite-encaps",
3148 const static char *const sr_pr_encaps_ip4_nodes[] = {
3149 "sr-pl-rewrite-encaps-v4",
3153 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3154 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3155 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3158 const static char *const sr_pr_insert_ip6_nodes[] = {
3159 "sr-pl-rewrite-insert",
3163 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3164 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3167 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3168 "sr-pl-rewrite-b-insert",
3172 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3173 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3176 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3177 "sr-pl-rewrite-b-encaps",
3181 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3182 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3185 /********************* SR Policy Rewrite initialization ***********************/
3187 * @brief SR Policy Rewrite initialization
3190 sr_policy_rewrite_init (vlib_main_t * vm)
3192 ip6_sr_main_t *sm = &sr_main;
3194 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3195 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3196 sizeof (ip6_address_t));
3198 /* Init SR VPO DPOs type */
3199 sr_pr_encaps_dpo_type =
3200 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3202 sr_pr_insert_dpo_type =
3203 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3205 sr_pr_bsid_encaps_dpo_type =
3206 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3208 sr_pr_bsid_insert_dpo_type =
3209 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3211 /* Register the L2 encaps node used in HW redirect */
3212 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3214 sm->fib_table_ip6 = (u32) ~ 0;
3215 sm->fib_table_ip4 = (u32) ~ 0;
3220 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3224 * fd.io coding-style-patch-verification: ON
3227 * eval: (c-set-style "gnu")