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 */
116 sr_set_source (ip6_address_t * address)
118 clib_memcpy (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
121 static clib_error_t *
122 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
123 vlib_cli_command_t * cmd)
125 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
128 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
131 return clib_error_return (0, "No address specified");
133 return clib_error_return (0, "No address specified");
137 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
138 .path = "set sr encaps source",
139 .short_help = "set sr encaps source addr <ip6_addr>",
140 .function = set_sr_src_command_fn,
144 /*********************** SR rewrite string computation ************************/
146 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
148 * @param sl is a vector of IPv6 addresses composing the Segment List
150 * @return precomputed rewrite string for encapsulation
153 compute_rewrite_encaps (ip6_address_t * sl)
156 ip6_sr_header_t *srh;
157 ip6_address_t *addrp, *this_address;
158 u32 header_length = 0;
162 header_length += IPv6_DEFAULT_HEADER_LENGTH;
163 if (vec_len (sl) > 1)
165 header_length += sizeof (ip6_sr_header_t);
166 header_length += vec_len (sl) * sizeof (ip6_address_t);
169 vec_validate (rs, header_length - 1);
171 iph = (ip6_header_t *) rs;
172 iph->ip_version_traffic_class_and_flow_label =
173 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
174 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
175 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
176 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
177 iph->protocol = IP_PROTOCOL_IPV6;
178 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
180 srh = (ip6_sr_header_t *) (iph + 1);
181 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
182 srh->protocol = IP_PROTOCOL_IPV6;
183 srh->type = ROUTING_HEADER_TYPE_SR;
184 srh->segments_left = vec_len (sl) - 1;
185 srh->first_segment = vec_len (sl) - 1;
186 srh->length = ((sizeof (ip6_sr_header_t) +
187 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
189 srh->reserved = 0x00;
190 addrp = srh->segments + vec_len (sl) - 1;
191 vec_foreach (this_address, sl)
193 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
196 iph->dst_address.as_u64[0] = sl->as_u64[0];
197 iph->dst_address.as_u64[1] = sl->as_u64[1];
202 * @brief SR rewrite string computation for SRH insertion (inline)
204 * @param sl is a vector of IPv6 addresses composing the Segment List
206 * @return precomputed rewrite string for SRH insertion
209 compute_rewrite_insert (ip6_address_t * sl)
211 ip6_sr_header_t *srh;
212 ip6_address_t *addrp, *this_address;
213 u32 header_length = 0;
217 header_length += sizeof (ip6_sr_header_t);
218 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
220 vec_validate (rs, header_length - 1);
222 srh = (ip6_sr_header_t *) rs;
223 srh->type = ROUTING_HEADER_TYPE_SR;
224 srh->segments_left = vec_len (sl);
225 srh->first_segment = vec_len (sl);
226 srh->length = ((sizeof (ip6_sr_header_t) +
227 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
229 srh->reserved = 0x0000;
230 addrp = srh->segments + vec_len (sl);
231 vec_foreach (this_address, sl)
233 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
240 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
242 * @param sl is a vector of IPv6 addresses composing the Segment List
244 * @return precomputed rewrite string for SRH insertion with BSID
247 compute_rewrite_bsid (ip6_address_t * sl)
249 ip6_sr_header_t *srh;
250 ip6_address_t *addrp, *this_address;
251 u32 header_length = 0;
255 header_length += sizeof (ip6_sr_header_t);
256 header_length += vec_len (sl) * sizeof (ip6_address_t);
258 vec_validate (rs, header_length - 1);
260 srh = (ip6_sr_header_t *) rs;
261 srh->type = ROUTING_HEADER_TYPE_SR;
262 srh->segments_left = vec_len (sl) - 1;
263 srh->first_segment = vec_len (sl) - 1;
264 srh->length = ((sizeof (ip6_sr_header_t) +
265 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
267 srh->reserved = 0x0000;
268 addrp = srh->segments + vec_len (sl) - 1;
269 vec_foreach (this_address, sl)
271 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
277 /*************************** SR LB helper functions **************************/
279 * @brief Creates a Segment List and adds it to an SR policy
281 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
282 * not necessarily unique. Hence there might be two Segment List within the
283 * same SR Policy with exactly the same segments and same weight.
285 * @param sr_policy is the SR policy where the SL will be added
286 * @param sl is a vector of IPv6 addresses composing the Segment List
287 * @param weight is the weight of the SegmentList (for load-balancing purposes)
288 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
290 * @return pointer to the just created segment list
292 static inline ip6_sr_sl_t *
293 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
296 ip6_sr_main_t *sm = &sr_main;
297 ip6_sr_sl_t *segment_list;
299 pool_get (sm->sid_lists, segment_list);
300 memset (segment_list, 0, sizeof (*segment_list));
302 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
304 /* Fill in segment list */
305 segment_list->weight =
306 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
307 segment_list->segments = vec_dup (sl);
311 segment_list->rewrite = compute_rewrite_encaps (sl);
312 segment_list->rewrite_bsid = segment_list->rewrite;
316 segment_list->rewrite = compute_rewrite_insert (sl);
317 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
321 dpo_reset (&segment_list->bsid_dpo);
322 dpo_reset (&segment_list->ip6_dpo);
323 dpo_reset (&segment_list->ip4_dpo);
327 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
328 segment_list - sm->sid_lists);
329 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
330 segment_list - sm->sid_lists);
331 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
332 DPO_PROTO_IP6, segment_list - sm->sid_lists);
336 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
337 segment_list - sm->sid_lists);
338 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
339 DPO_PROTO_IP6, segment_list - sm->sid_lists);
346 * @brief Updates the Load Balancer after an SR Policy change
348 * @param sr_policy is the modified SR Policy
351 update_lb (ip6_sr_policy_t * sr_policy)
353 flow_hash_config_t fhc;
355 ip6_sr_sl_t *segment_list;
356 ip6_sr_main_t *sm = &sr_main;
357 load_balance_path_t path;
358 path.path_index = FIB_NODE_INDEX_INVALID;
359 load_balance_path_t *ip4_path_vector = 0;
360 load_balance_path_t *ip6_path_vector = 0;
361 load_balance_path_t *b_path_vector = 0;
363 /* In case LB does not exist, create it */
364 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
367 .fp_proto = FIB_PROTOCOL_IP6,
370 .ip6 = sr_policy->bsid,
374 /* Add FIB entry for BSID */
375 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
378 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
379 load_balance_create (0, DPO_PROTO_IP6, fhc));
381 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
382 load_balance_create (0, DPO_PROTO_IP6, fhc));
384 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
385 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
386 sr_policy->fib_table),
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->bsid_dpo);
391 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
394 FIB_ENTRY_FLAG_EXCLUSIVE,
395 &sr_policy->ip6_dpo);
397 if (sr_policy->is_encap)
399 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
400 load_balance_create (0, DPO_PROTO_IP4, fhc));
402 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
405 FIB_ENTRY_FLAG_EXCLUSIVE,
406 &sr_policy->ip4_dpo);
411 /* Create the LB path vector */
412 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
413 vec_foreach (sl_index, sr_policy->segments_lists)
415 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
416 path.path_dpo = segment_list->bsid_dpo;
417 path.path_weight = segment_list->weight;
418 vec_add1 (b_path_vector, path);
419 path.path_dpo = segment_list->ip6_dpo;
420 vec_add1 (ip6_path_vector, path);
421 if (sr_policy->is_encap)
423 path.path_dpo = segment_list->ip4_dpo;
424 vec_add1 (ip4_path_vector, path);
428 /* Update LB multipath */
429 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
430 LOAD_BALANCE_FLAG_NONE);
431 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
432 LOAD_BALANCE_FLAG_NONE);
433 if (sr_policy->is_encap)
434 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
435 LOAD_BALANCE_FLAG_NONE);
438 vec_free (b_path_vector);
439 vec_free (ip6_path_vector);
440 vec_free (ip4_path_vector);
445 * @brief Updates the Replicate DPO after an SR Policy change
447 * @param sr_policy is the modified SR Policy (type spray)
450 update_replicate (ip6_sr_policy_t * sr_policy)
453 ip6_sr_sl_t *segment_list;
454 ip6_sr_main_t *sm = &sr_main;
455 load_balance_path_t path;
456 path.path_index = FIB_NODE_INDEX_INVALID;
457 load_balance_path_t *b_path_vector = 0;
458 load_balance_path_t *ip6_path_vector = 0;
459 load_balance_path_t *ip4_path_vector = 0;
461 /* In case LB does not exist, create it */
462 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
464 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
465 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
467 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
468 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
470 /* Update FIB entry's DPO to point to SR without LB */
472 .fp_proto = FIB_PROTOCOL_IP6,
475 .ip6 = sr_policy->bsid,
478 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
479 sr_policy->fib_table),
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->bsid_dpo);
484 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
487 FIB_ENTRY_FLAG_EXCLUSIVE,
488 &sr_policy->ip6_dpo);
490 if (sr_policy->is_encap)
492 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
493 replicate_create (0, DPO_PROTO_IP4));
495 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
498 FIB_ENTRY_FLAG_EXCLUSIVE,
499 &sr_policy->ip4_dpo);
504 /* Create the replicate path vector */
505 path.path_weight = 1;
506 vec_foreach (sl_index, sr_policy->segments_lists)
508 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
509 path.path_dpo = segment_list->bsid_dpo;
510 vec_add1 (b_path_vector, path);
511 path.path_dpo = segment_list->ip6_dpo;
512 vec_add1 (ip6_path_vector, path);
513 if (sr_policy->is_encap)
515 path.path_dpo = segment_list->ip4_dpo;
516 vec_add1 (ip4_path_vector, path);
520 /* Update replicate multipath */
521 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
522 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
523 if (sr_policy->is_encap)
524 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
527 /******************************* SR rewrite API *******************************/
528 /* Three functions for handling sr policies:
532 * All of them are API. CLI function on sr_policy_command_fn */
535 * @brief Create a new SR policy
537 * @param bsid is the bindingSID of the SR Policy
538 * @param segments is a vector of IPv6 address composing the segment list
539 * @param weight is the weight of the sid list. optional.
540 * @param behavior is the behavior of the SR policy. (default//spray)
541 * @param fib_table is the VRF where to install the FIB entry for the BSID
542 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
544 * @return 0 if correct, else error
547 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
548 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
550 ip6_sr_main_t *sm = &sr_main;
551 ip6_sr_policy_t *sr_policy = 0;
554 /* Search for existing keys (BSID) */
555 p = mhash_get (&sm->sr_policies_index_hash, bsid);
558 /* Add SR policy that already exists; complain */
562 /* Search collision in FIB entries */
563 /* Explanation: It might be possible that some other entity has already
564 * created a route for the BSID. This in theory is impossible, but in
565 * practise we could see it. Assert it and scream if needed */
567 .fp_proto = FIB_PROTOCOL_IP6,
574 /* Lookup the FIB index associated to the table selected */
575 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
576 (fib_table != (u32) ~ 0 ? fib_table : 0));
580 /* Lookup whether there exists an entry for the BSID */
581 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
582 if (FIB_NODE_INDEX_INVALID != fei)
583 return -12; //There is an entry for such lookup
585 /* Add an SR policy object */
586 pool_get (sm->sr_policies, sr_policy);
587 memset (sr_policy, 0, sizeof (*sr_policy));
588 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
589 sr_policy->type = behavior;
590 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
591 sr_policy->is_encap = is_encap;
594 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
597 /* Create a segment list and add the index to the SR policy */
598 create_sl (sr_policy, segments, weight, is_encap);
600 /* If FIB doesnt exist, create them */
601 if (sm->fib_table_ip6 == (u32) ~ 0)
603 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
605 "SRv6 steering of IP6 prefixes through BSIDs");
606 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
608 "SRv6 steering of IP4 prefixes through BSIDs");
611 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
612 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
613 update_lb (sr_policy);
614 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
615 update_replicate (sr_policy);
620 * @brief Delete a SR policy
622 * @param bsid is the bindingSID of the SR Policy
623 * @param index is the index of the SR policy
625 * @return 0 if correct, else error
628 sr_policy_del (ip6_address_t * bsid, u32 index)
630 ip6_sr_main_t *sm = &sr_main;
631 ip6_sr_policy_t *sr_policy = 0;
632 ip6_sr_sl_t *segment_list;
638 p = mhash_get (&sm->sr_policies_index_hash, bsid);
640 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
646 sr_policy = pool_elt_at_index (sm->sr_policies, index);
651 /* Remove BindingSID FIB entry */
653 .fp_proto = FIB_PROTOCOL_IP6,
656 .ip6 = sr_policy->bsid,
661 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
662 sr_policy->fib_table),
663 &pfx, FIB_SOURCE_SR);
665 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
667 if (sr_policy->is_encap)
668 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
670 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
672 dpo_reset (&sr_policy->bsid_dpo);
673 dpo_reset (&sr_policy->ip4_dpo);
674 dpo_reset (&sr_policy->ip6_dpo);
677 /* Clean SID Lists */
678 vec_foreach (sl_index, sr_policy->segments_lists)
680 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
681 vec_free (segment_list->segments);
682 vec_free (segment_list->rewrite);
683 if (!sr_policy->is_encap)
684 vec_free (segment_list->rewrite_bsid);
685 pool_put_index (sm->sid_lists, *sl_index);
688 /* Remove SR policy entry */
689 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
690 pool_put (sm->sr_policies, sr_policy);
692 /* If FIB empty unlock it */
693 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
695 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
696 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
697 sm->fib_table_ip6 = (u32) ~ 0;
698 sm->fib_table_ip4 = (u32) ~ 0;
705 * @brief Modify an existing SR policy
707 * The possible modifications are adding a new Segment List, modifying an
708 * existing Segment List (modify the weight only) and delete a given
709 * Segment List from the SR Policy.
711 * @param bsid is the bindingSID of the SR Policy
712 * @param index is the index of the SR policy
713 * @param fib_table is the VRF where to install the FIB entry for the BSID
714 * @param operation is the operation to perform (among the top ones)
715 * @param segments is a vector of IPv6 address composing the segment list
716 * @param sl_index is the index of the Segment List to modify/delete
717 * @param weight is the weight of the sid list. optional.
718 * @param is_encap Mode. Encapsulation or SRH insertion.
720 * @return 0 if correct, else error
723 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
724 u8 operation, ip6_address_t * segments, u32 sl_index,
727 ip6_sr_main_t *sm = &sr_main;
728 ip6_sr_policy_t *sr_policy = 0;
729 ip6_sr_sl_t *segment_list;
730 u32 *sl_index_iterate;
735 p = mhash_get (&sm->sr_policies_index_hash, bsid);
737 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
743 sr_policy = pool_elt_at_index (sm->sr_policies, index);
748 if (operation == 1) /* Add SR List to an existing SR policy */
750 /* Create the new SL */
752 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
754 /* Create a new LB DPO */
755 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
756 update_lb (sr_policy);
757 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
758 update_replicate (sr_policy);
760 else if (operation == 2) /* Delete SR List from an existing SR policy */
762 /* Check that currently there are more than one SID list */
763 if (vec_len (sr_policy->segments_lists) == 1)
766 /* Check that the SR list does exist and is assigned to the sr policy */
767 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
768 if (*sl_index_iterate == sl_index)
771 if (*sl_index_iterate != sl_index)
774 /* Remove the lucky SR list that is being kicked out */
775 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
776 vec_free (segment_list->segments);
777 vec_free (segment_list->rewrite);
778 if (!sr_policy->is_encap)
779 vec_free (segment_list->rewrite_bsid);
780 pool_put_index (sm->sid_lists, sl_index);
781 vec_del1 (sr_policy->segments_lists,
782 sl_index_iterate - sr_policy->segments_lists);
784 /* Create a new LB DPO */
785 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
786 update_lb (sr_policy);
787 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
788 update_replicate (sr_policy);
790 else if (operation == 3) /* Modify the weight of an existing SR List */
792 /* Find the corresponding SL */
793 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
794 if (*sl_index_iterate == sl_index)
797 if (*sl_index_iterate != sl_index)
800 /* Change the weight */
801 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
802 segment_list->weight = weight;
805 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
806 update_lb (sr_policy);
808 else /* Incorrect op. */
815 * @brief CLI for 'sr policies' command family
817 static clib_error_t *
818 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
819 vlib_cli_command_t * cmd)
822 char is_del = 0, is_add = 0, is_mod = 0;
824 ip6_address_t bsid, next_address;
825 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
826 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
827 ip6_address_t *segments = 0, *this_seg;
832 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
834 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
836 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
838 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
841 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
843 else if (!is_add && !policy_set
844 && unformat (input, "index %d", &sr_policy_index))
846 else if (unformat (input, "weight %d", &weight));
848 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
850 vec_add2 (segments, this_seg, 1);
851 clib_memcpy (this_seg->as_u8, next_address.as_u8,
854 else if (unformat (input, "add sl"))
856 else if (unformat (input, "del sl index %d", &sl_index))
858 else if (unformat (input, "mod sl index %d", &sl_index))
860 else if (fib_table == (u32) ~ 0
861 && unformat (input, "fib-table %d", &fib_table));
862 else if (unformat (input, "encap"))
864 else if (unformat (input, "insert"))
866 else if (unformat (input, "spray"))
872 if (!is_add && !is_mod && !is_del)
873 return clib_error_return (0, "Incorrect CLI");
876 return clib_error_return (0, "No SR policy BSID or index specified");
880 if (vec_len (segments) == 0)
881 return clib_error_return (0, "No Segment List specified");
882 rv = sr_policy_add (&bsid, segments, weight,
883 (is_spray ? SR_POLICY_TYPE_SPRAY :
884 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
887 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
892 return clib_error_return (0, "No SL modification specified");
893 if (operation != 1 && sl_index == (u32) ~ 0)
894 return clib_error_return (0, "No Segment List index specified");
895 if (operation == 1 && vec_len (segments) == 0)
896 return clib_error_return (0, "No Segment List specified");
897 if (operation == 3 && weight == (u32) ~ 0)
898 return clib_error_return (0, "No new weight for the SL specified");
899 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
900 sr_policy_index, fib_table, operation, segments,
911 return clib_error_return (0,
912 "There is already a FIB entry for the BindingSID address.\n"
913 "The SR policy could not be created.");
915 return clib_error_return (0, "The specified FIB table does not exist.");
917 return clib_error_return (0,
918 "The selected SR policy only contains ONE segment list. "
919 "Please remove the SR policy instead");
921 return clib_error_return (0,
922 "Could not delete the segment list. "
923 "It is not associated with that SR policy.");
925 return clib_error_return (0,
926 "Could not modify the segment list. "
927 "The given SL is not associated with such SR policy.");
929 return clib_error_return (0, "BUG: sr policy returns %d", rv);
935 VLIB_CLI_COMMAND (sr_policy_command, static) = {
937 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
938 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
940 "Manipulation of SR policies.\n"
941 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
942 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
943 "Segment Routing policies might be of type encapsulation or srh insertion\n"
944 "Each SR policy will be associated with a unique BindingSID.\n"
945 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
946 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
947 "The add command will create a SR policy with its first segment list (sl)\n"
948 "The mod command allows you to add, remove, or modify the existing segment lists\n"
949 "within an SR policy.\n"
950 "The del command allows you to delete a SR policy along with all its associated\n"
952 .function = sr_policy_command_fn,
957 * @brief CLI to display onscreen all the SR policies
959 static clib_error_t *
960 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
961 vlib_cli_command_t * cmd)
963 ip6_sr_main_t *sm = &sr_main;
965 ip6_sr_sl_t *segment_list = 0;
966 ip6_sr_policy_t *sr_policy = 0;
967 ip6_sr_policy_t **vec_policies = 0;
972 vlib_cli_output (vm, "SR policies:");
975 pool_foreach (sr_policy, sm->sr_policies,
976 {vec_add1 (vec_policies, sr_policy); } );
979 vec_foreach_index (i, vec_policies)
981 sr_policy = vec_policies[i];
982 vlib_cli_output (vm, "[%u].-\tBSID: %U",
983 (u32) (sr_policy - sm->sr_policies),
984 format_ip6_address, &sr_policy->bsid);
985 vlib_cli_output (vm, "\tBehavior: %s",
986 (sr_policy->is_encap ? "Encapsulation" :
988 vlib_cli_output (vm, "\tType: %s",
990 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
991 vlib_cli_output (vm, "\tFIB table: %u",
992 (sr_policy->fib_table !=
993 (u32) ~ 0 ? sr_policy->fib_table : 0));
994 vlib_cli_output (vm, "\tSegment Lists:");
995 vec_foreach (sl_index, sr_policy->segments_lists)
998 s = format (s, "\t[%u].- ", *sl_index);
999 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1000 s = format (s, "< ");
1001 vec_foreach (addr, segment_list->segments)
1003 s = format (s, "%U, ", format_ip6_address, addr);
1005 s = format (s, "\b\b > ");
1006 s = format (s, "weight: %u", segment_list->weight);
1007 vlib_cli_output (vm, " %s", s);
1009 vlib_cli_output (vm, "-----------");
1015 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1016 .path = "show sr policies",
1017 .short_help = "show sr policies",
1018 .function = show_sr_policies_command_fn,
1022 /*************************** SR rewrite graph node ****************************/
1024 * @brief Trace for the SR Policy Rewrite graph node
1027 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1030 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1031 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1032 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1035 (s, "SR-policy-rewrite: src %U dst %U",
1036 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1042 * @brief IPv6 encapsulation processing as per RFC2473
1044 static_always_inline void
1045 encaps_processing_v6 (vlib_node_runtime_t * node,
1047 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1051 ip0_encap->hop_limit -= 1;
1053 ip0->payload_length + sizeof (ip6_header_t) +
1054 clib_net_to_host_u16 (ip0_encap->payload_length);
1055 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1056 ip0->ip_version_traffic_class_and_flow_label =
1057 ip0_encap->ip_version_traffic_class_and_flow_label;
1061 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1064 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1065 vlib_frame_t * from_frame)
1067 ip6_sr_main_t *sm = &sr_main;
1068 u32 n_left_from, next_index, *from, *to_next;
1070 from = vlib_frame_vector_args (from_frame);
1071 n_left_from = from_frame->n_vectors;
1073 next_index = node->cached_next_index;
1075 int encap_pkts = 0, bsid_pkts = 0;
1077 while (n_left_from > 0)
1081 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1084 while (n_left_from >= 8 && n_left_to_next >= 4)
1086 u32 bi0, bi1, bi2, bi3;
1087 vlib_buffer_t *b0, *b1, *b2, *b3;
1088 u32 next0, next1, next2, next3;
1089 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1090 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1091 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1092 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1094 /* Prefetch next iteration. */
1096 vlib_buffer_t *p4, *p5, *p6, *p7;
1098 p4 = vlib_get_buffer (vm, from[4]);
1099 p5 = vlib_get_buffer (vm, from[5]);
1100 p6 = vlib_get_buffer (vm, from[6]);
1101 p7 = vlib_get_buffer (vm, from[7]);
1103 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1104 vlib_prefetch_buffer_header (p4, LOAD);
1105 vlib_prefetch_buffer_header (p5, LOAD);
1106 vlib_prefetch_buffer_header (p6, LOAD);
1107 vlib_prefetch_buffer_header (p7, LOAD);
1109 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1110 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1111 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1112 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1115 to_next[0] = bi0 = from[0];
1116 to_next[1] = bi1 = from[1];
1117 to_next[2] = bi2 = from[2];
1118 to_next[3] = bi3 = from[3];
1122 n_left_to_next -= 4;
1124 b0 = vlib_get_buffer (vm, bi0);
1125 b1 = vlib_get_buffer (vm, bi1);
1126 b2 = vlib_get_buffer (vm, bi2);
1127 b3 = vlib_get_buffer (vm, bi3);
1130 pool_elt_at_index (sm->sid_lists,
1131 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1133 pool_elt_at_index (sm->sid_lists,
1134 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1136 pool_elt_at_index (sm->sid_lists,
1137 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1139 pool_elt_at_index (sm->sid_lists,
1140 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1142 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1143 vec_len (sl0->rewrite));
1144 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1145 vec_len (sl1->rewrite));
1146 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1147 vec_len (sl2->rewrite));
1148 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1149 vec_len (sl3->rewrite));
1151 ip0_encap = vlib_buffer_get_current (b0);
1152 ip1_encap = vlib_buffer_get_current (b1);
1153 ip2_encap = vlib_buffer_get_current (b2);
1154 ip3_encap = vlib_buffer_get_current (b3);
1156 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1157 sl0->rewrite, vec_len (sl0->rewrite));
1158 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1159 sl1->rewrite, vec_len (sl1->rewrite));
1160 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1161 sl2->rewrite, vec_len (sl2->rewrite));
1162 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1163 sl3->rewrite, vec_len (sl3->rewrite));
1165 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1166 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1167 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1168 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1170 ip0 = vlib_buffer_get_current (b0);
1171 ip1 = vlib_buffer_get_current (b1);
1172 ip2 = vlib_buffer_get_current (b2);
1173 ip3 = vlib_buffer_get_current (b3);
1175 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1176 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1177 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1178 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1180 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1182 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1184 sr_policy_rewrite_trace_t *tr =
1185 vlib_add_trace (vm, node, b0, sizeof (*tr));
1186 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1187 sizeof (tr->src.as_u8));
1188 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1189 sizeof (tr->dst.as_u8));
1192 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1194 sr_policy_rewrite_trace_t *tr =
1195 vlib_add_trace (vm, node, b1, sizeof (*tr));
1196 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1197 sizeof (tr->src.as_u8));
1198 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1199 sizeof (tr->dst.as_u8));
1202 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1204 sr_policy_rewrite_trace_t *tr =
1205 vlib_add_trace (vm, node, b2, sizeof (*tr));
1206 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1207 sizeof (tr->src.as_u8));
1208 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1209 sizeof (tr->dst.as_u8));
1212 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1214 sr_policy_rewrite_trace_t *tr =
1215 vlib_add_trace (vm, node, b3, sizeof (*tr));
1216 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1217 sizeof (tr->src.as_u8));
1218 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1219 sizeof (tr->dst.as_u8));
1224 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1225 n_left_to_next, bi0, bi1, bi2, bi3,
1226 next0, next1, next2, next3);
1229 /* Single loop for potentially the last three packets */
1230 while (n_left_from > 0 && n_left_to_next > 0)
1234 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1236 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1243 n_left_to_next -= 1;
1244 b0 = vlib_get_buffer (vm, bi0);
1247 pool_elt_at_index (sm->sid_lists,
1248 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1249 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1250 vec_len (sl0->rewrite));
1252 ip0_encap = vlib_buffer_get_current (b0);
1254 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1255 sl0->rewrite, vec_len (sl0->rewrite));
1256 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1258 ip0 = vlib_buffer_get_current (b0);
1260 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1262 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1263 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1265 sr_policy_rewrite_trace_t *tr =
1266 vlib_add_trace (vm, node, b0, sizeof (*tr));
1267 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1268 sizeof (tr->src.as_u8));
1269 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1270 sizeof (tr->dst.as_u8));
1274 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1275 n_left_to_next, bi0, next0);
1278 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1281 /* Update counters */
1282 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1283 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1285 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1286 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1289 return from_frame->n_vectors;
1293 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1294 .function = sr_policy_rewrite_encaps,
1295 .name = "sr-pl-rewrite-encaps",
1296 .vector_size = sizeof (u32),
1297 .format_trace = format_sr_policy_rewrite_trace,
1298 .type = VLIB_NODE_TYPE_INTERNAL,
1299 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1300 .error_strings = sr_policy_rewrite_error_strings,
1301 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1303 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1304 foreach_sr_policy_rewrite_next
1311 * @brief IPv4 encapsulation processing as per RFC2473
1313 static_always_inline void
1314 encaps_processing_v4 (vlib_node_runtime_t * node,
1316 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1319 ip6_sr_header_t *sr0;
1323 /* Inner IPv4: Decrement TTL & update checksum */
1324 ip0_encap->ttl -= 1;
1325 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1326 checksum0 += checksum0 >= 0xffff;
1327 ip0_encap->checksum = checksum0;
1329 /* Outer IPv6: Update length, FL, proto */
1330 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1331 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1332 ip0->ip_version_traffic_class_and_flow_label =
1333 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1334 ((ip0_encap->tos & 0xFF) << 20));
1335 sr0 = (void *) (ip0 + 1);
1336 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1340 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1343 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1344 vlib_frame_t * from_frame)
1346 ip6_sr_main_t *sm = &sr_main;
1347 u32 n_left_from, next_index, *from, *to_next;
1349 from = vlib_frame_vector_args (from_frame);
1350 n_left_from = from_frame->n_vectors;
1352 next_index = node->cached_next_index;
1354 int encap_pkts = 0, bsid_pkts = 0;
1356 while (n_left_from > 0)
1360 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1363 while (n_left_from >= 8 && n_left_to_next >= 4)
1365 u32 bi0, bi1, bi2, bi3;
1366 vlib_buffer_t *b0, *b1, *b2, *b3;
1367 u32 next0, next1, next2, next3;
1368 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1369 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1370 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1371 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1373 /* Prefetch next iteration. */
1375 vlib_buffer_t *p4, *p5, *p6, *p7;
1377 p4 = vlib_get_buffer (vm, from[4]);
1378 p5 = vlib_get_buffer (vm, from[5]);
1379 p6 = vlib_get_buffer (vm, from[6]);
1380 p7 = vlib_get_buffer (vm, from[7]);
1382 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1383 vlib_prefetch_buffer_header (p4, LOAD);
1384 vlib_prefetch_buffer_header (p5, LOAD);
1385 vlib_prefetch_buffer_header (p6, LOAD);
1386 vlib_prefetch_buffer_header (p7, LOAD);
1388 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1389 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1390 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1391 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1394 to_next[0] = bi0 = from[0];
1395 to_next[1] = bi1 = from[1];
1396 to_next[2] = bi2 = from[2];
1397 to_next[3] = bi3 = from[3];
1401 n_left_to_next -= 4;
1403 b0 = vlib_get_buffer (vm, bi0);
1404 b1 = vlib_get_buffer (vm, bi1);
1405 b2 = vlib_get_buffer (vm, bi2);
1406 b3 = vlib_get_buffer (vm, bi3);
1409 pool_elt_at_index (sm->sid_lists,
1410 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1412 pool_elt_at_index (sm->sid_lists,
1413 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1415 pool_elt_at_index (sm->sid_lists,
1416 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1418 pool_elt_at_index (sm->sid_lists,
1419 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1420 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1421 vec_len (sl0->rewrite));
1422 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1423 vec_len (sl1->rewrite));
1424 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1425 vec_len (sl2->rewrite));
1426 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1427 vec_len (sl3->rewrite));
1429 ip0_encap = vlib_buffer_get_current (b0);
1430 ip1_encap = vlib_buffer_get_current (b1);
1431 ip2_encap = vlib_buffer_get_current (b2);
1432 ip3_encap = vlib_buffer_get_current (b3);
1434 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1435 sl0->rewrite, vec_len (sl0->rewrite));
1436 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1437 sl1->rewrite, vec_len (sl1->rewrite));
1438 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1439 sl2->rewrite, vec_len (sl2->rewrite));
1440 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1441 sl3->rewrite, vec_len (sl3->rewrite));
1443 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1444 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1445 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1446 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1448 ip0 = vlib_buffer_get_current (b0);
1449 ip1 = vlib_buffer_get_current (b1);
1450 ip2 = vlib_buffer_get_current (b2);
1451 ip3 = vlib_buffer_get_current (b3);
1453 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1454 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1455 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1456 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1458 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1460 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1462 sr_policy_rewrite_trace_t *tr =
1463 vlib_add_trace (vm, node, b0, sizeof (*tr));
1464 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1465 sizeof (tr->src.as_u8));
1466 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1467 sizeof (tr->dst.as_u8));
1470 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1472 sr_policy_rewrite_trace_t *tr =
1473 vlib_add_trace (vm, node, b1, sizeof (*tr));
1474 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1475 sizeof (tr->src.as_u8));
1476 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1477 sizeof (tr->dst.as_u8));
1480 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1482 sr_policy_rewrite_trace_t *tr =
1483 vlib_add_trace (vm, node, b2, sizeof (*tr));
1484 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1485 sizeof (tr->src.as_u8));
1486 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1487 sizeof (tr->dst.as_u8));
1490 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1492 sr_policy_rewrite_trace_t *tr =
1493 vlib_add_trace (vm, node, b3, sizeof (*tr));
1494 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1495 sizeof (tr->src.as_u8));
1496 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1497 sizeof (tr->dst.as_u8));
1502 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1503 n_left_to_next, bi0, bi1, bi2, bi3,
1504 next0, next1, next2, next3);
1507 /* Single loop for potentially the last three packets */
1508 while (n_left_from > 0 && n_left_to_next > 0)
1512 ip6_header_t *ip0 = 0;
1513 ip4_header_t *ip0_encap = 0;
1515 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1522 n_left_to_next -= 1;
1523 b0 = vlib_get_buffer (vm, bi0);
1526 pool_elt_at_index (sm->sid_lists,
1527 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1528 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1529 vec_len (sl0->rewrite));
1531 ip0_encap = vlib_buffer_get_current (b0);
1533 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1534 sl0->rewrite, vec_len (sl0->rewrite));
1535 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1537 ip0 = vlib_buffer_get_current (b0);
1539 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1541 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1542 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1544 sr_policy_rewrite_trace_t *tr =
1545 vlib_add_trace (vm, node, b0, sizeof (*tr));
1546 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1547 sizeof (tr->src.as_u8));
1548 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1549 sizeof (tr->dst.as_u8));
1553 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1554 n_left_to_next, bi0, next0);
1557 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1560 /* Update counters */
1561 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1562 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1564 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1565 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1568 return from_frame->n_vectors;
1572 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1573 .function = sr_policy_rewrite_encaps_v4,
1574 .name = "sr-pl-rewrite-encaps-v4",
1575 .vector_size = sizeof (u32),
1576 .format_trace = format_sr_policy_rewrite_trace,
1577 .type = VLIB_NODE_TYPE_INTERNAL,
1578 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1579 .error_strings = sr_policy_rewrite_error_strings,
1580 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1582 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1583 foreach_sr_policy_rewrite_next
1590 ip_flow_hash (void *data)
1592 ip4_header_t *iph = (ip4_header_t *) data;
1594 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1595 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1597 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1603 return (*((u64 *) m) & 0xffffffffffff);
1607 l2_flow_hash (vlib_buffer_t * b0)
1609 ethernet_header_t *eh;
1611 uword is_ip, eh_size;
1614 eh = vlib_buffer_get_current (b0);
1615 eh_type = clib_net_to_host_u16 (eh->type);
1616 eh_size = ethernet_buffer_header_size (b0);
1618 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1620 /* since we have 2 cache lines, use them */
1622 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1626 b = mac_to_u64 ((u8 *) eh->dst_address);
1627 c = mac_to_u64 ((u8 *) eh->src_address);
1628 hash_mix64 (a, b, c);
1634 * @brief Graph node for applying a SR policy into a L2 frame
1637 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1638 vlib_frame_t * from_frame)
1640 ip6_sr_main_t *sm = &sr_main;
1641 u32 n_left_from, next_index, *from, *to_next;
1643 from = vlib_frame_vector_args (from_frame);
1644 n_left_from = from_frame->n_vectors;
1646 next_index = node->cached_next_index;
1648 int encap_pkts = 0, bsid_pkts = 0;
1650 while (n_left_from > 0)
1654 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1657 while (n_left_from >= 8 && n_left_to_next >= 4)
1659 u32 bi0, bi1, bi2, bi3;
1660 vlib_buffer_t *b0, *b1, *b2, *b3;
1661 u32 next0, next1, next2, next3;
1662 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1663 ethernet_header_t *en0, *en1, *en2, *en3;
1664 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1665 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1666 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1667 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1669 /* Prefetch next iteration. */
1671 vlib_buffer_t *p4, *p5, *p6, *p7;
1673 p4 = vlib_get_buffer (vm, from[4]);
1674 p5 = vlib_get_buffer (vm, from[5]);
1675 p6 = vlib_get_buffer (vm, from[6]);
1676 p7 = vlib_get_buffer (vm, from[7]);
1678 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1679 vlib_prefetch_buffer_header (p4, LOAD);
1680 vlib_prefetch_buffer_header (p5, LOAD);
1681 vlib_prefetch_buffer_header (p6, LOAD);
1682 vlib_prefetch_buffer_header (p7, LOAD);
1684 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1685 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1686 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1687 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1690 to_next[0] = bi0 = from[0];
1691 to_next[1] = bi1 = from[1];
1692 to_next[2] = bi2 = from[2];
1693 to_next[3] = bi3 = from[3];
1697 n_left_to_next -= 4;
1699 b0 = vlib_get_buffer (vm, bi0);
1700 b1 = vlib_get_buffer (vm, bi1);
1701 b2 = vlib_get_buffer (vm, bi2);
1702 b3 = vlib_get_buffer (vm, bi3);
1704 sp0 = pool_elt_at_index (sm->sr_policies,
1705 sm->sw_iface_sr_policies[vnet_buffer
1709 sp1 = pool_elt_at_index (sm->sr_policies,
1710 sm->sw_iface_sr_policies[vnet_buffer
1714 sp2 = pool_elt_at_index (sm->sr_policies,
1715 sm->sw_iface_sr_policies[vnet_buffer
1719 sp3 = pool_elt_at_index (sm->sr_policies,
1720 sm->sw_iface_sr_policies[vnet_buffer
1724 if (vec_len (sp0->segments_lists) == 1)
1725 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1728 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1729 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1730 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1731 (vec_len (sp0->segments_lists) - 1))];
1734 if (vec_len (sp1->segments_lists) == 1)
1735 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1738 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1739 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1740 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1741 (vec_len (sp1->segments_lists) - 1))];
1744 if (vec_len (sp2->segments_lists) == 1)
1745 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1748 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1749 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1750 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1751 (vec_len (sp2->segments_lists) - 1))];
1754 if (vec_len (sp3->segments_lists) == 1)
1755 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1758 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1759 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1760 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1761 (vec_len (sp3->segments_lists) - 1))];
1765 pool_elt_at_index (sm->sid_lists,
1766 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1768 pool_elt_at_index (sm->sid_lists,
1769 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1771 pool_elt_at_index (sm->sid_lists,
1772 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1774 pool_elt_at_index (sm->sid_lists,
1775 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1777 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1778 vec_len (sl0->rewrite));
1779 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1780 vec_len (sl1->rewrite));
1781 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1782 vec_len (sl2->rewrite));
1783 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1784 vec_len (sl3->rewrite));
1786 en0 = vlib_buffer_get_current (b0);
1787 en1 = vlib_buffer_get_current (b1);
1788 en2 = vlib_buffer_get_current (b2);
1789 en3 = vlib_buffer_get_current (b3);
1791 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1792 vec_len (sl0->rewrite));
1793 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1794 vec_len (sl1->rewrite));
1795 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1796 vec_len (sl2->rewrite));
1797 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1798 vec_len (sl3->rewrite));
1800 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1801 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1802 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1803 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1805 ip0 = vlib_buffer_get_current (b0);
1806 ip1 = vlib_buffer_get_current (b1);
1807 ip2 = vlib_buffer_get_current (b2);
1808 ip3 = vlib_buffer_get_current (b3);
1810 ip0->payload_length =
1811 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1812 ip1->payload_length =
1813 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1814 ip2->payload_length =
1815 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1816 ip3->payload_length =
1817 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1819 sr0 = (void *) (ip0 + 1);
1820 sr1 = (void *) (ip1 + 1);
1821 sr2 = (void *) (ip2 + 1);
1822 sr3 = (void *) (ip3 + 1);
1824 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1825 IP_PROTOCOL_IP6_NONXT;
1827 /* Which Traffic class and flow label do I set ? */
1828 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1830 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1832 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1834 sr_policy_rewrite_trace_t *tr =
1835 vlib_add_trace (vm, node, b0, sizeof (*tr));
1836 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1837 sizeof (tr->src.as_u8));
1838 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1839 sizeof (tr->dst.as_u8));
1842 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1844 sr_policy_rewrite_trace_t *tr =
1845 vlib_add_trace (vm, node, b1, sizeof (*tr));
1846 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1847 sizeof (tr->src.as_u8));
1848 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1849 sizeof (tr->dst.as_u8));
1852 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1854 sr_policy_rewrite_trace_t *tr =
1855 vlib_add_trace (vm, node, b2, sizeof (*tr));
1856 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1857 sizeof (tr->src.as_u8));
1858 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1859 sizeof (tr->dst.as_u8));
1862 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1864 sr_policy_rewrite_trace_t *tr =
1865 vlib_add_trace (vm, node, b3, sizeof (*tr));
1866 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1867 sizeof (tr->src.as_u8));
1868 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1869 sizeof (tr->dst.as_u8));
1874 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1875 n_left_to_next, bi0, bi1, bi2, bi3,
1876 next0, next1, next2, next3);
1879 /* Single loop for potentially the last three packets */
1880 while (n_left_from > 0 && n_left_to_next > 0)
1884 ip6_header_t *ip0 = 0;
1885 ip6_sr_header_t *sr0;
1886 ethernet_header_t *en0;
1887 ip6_sr_policy_t *sp0;
1889 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1896 n_left_to_next -= 1;
1897 b0 = vlib_get_buffer (vm, bi0);
1899 /* Find the SR policy */
1900 sp0 = pool_elt_at_index (sm->sr_policies,
1901 sm->sw_iface_sr_policies[vnet_buffer
1905 /* In case there is more than one SL, LB among them */
1906 if (vec_len (sp0->segments_lists) == 1)
1907 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1910 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1911 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1912 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1913 (vec_len (sp0->segments_lists) - 1))];
1916 pool_elt_at_index (sm->sid_lists,
1917 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1918 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1919 vec_len (sl0->rewrite));
1921 en0 = vlib_buffer_get_current (b0);
1923 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1924 vec_len (sl0->rewrite));
1926 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1928 ip0 = vlib_buffer_get_current (b0);
1930 ip0->payload_length =
1931 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1933 sr0 = (void *) (ip0 + 1);
1934 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1936 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1937 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1939 sr_policy_rewrite_trace_t *tr =
1940 vlib_add_trace (vm, node, b0, sizeof (*tr));
1941 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1942 sizeof (tr->src.as_u8));
1943 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1944 sizeof (tr->dst.as_u8));
1948 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1949 n_left_to_next, bi0, next0);
1952 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1955 /* Update counters */
1956 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1957 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1959 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1960 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1963 return from_frame->n_vectors;
1967 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1968 .function = sr_policy_rewrite_encaps_l2,
1969 .name = "sr-pl-rewrite-encaps-l2",
1970 .vector_size = sizeof (u32),
1971 .format_trace = format_sr_policy_rewrite_trace,
1972 .type = VLIB_NODE_TYPE_INTERNAL,
1973 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1974 .error_strings = sr_policy_rewrite_error_strings,
1975 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1977 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1978 foreach_sr_policy_rewrite_next
1985 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1988 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1989 vlib_frame_t * from_frame)
1991 ip6_sr_main_t *sm = &sr_main;
1992 u32 n_left_from, next_index, *from, *to_next;
1994 from = vlib_frame_vector_args (from_frame);
1995 n_left_from = from_frame->n_vectors;
1997 next_index = node->cached_next_index;
1999 int insert_pkts = 0, bsid_pkts = 0;
2001 while (n_left_from > 0)
2005 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2008 while (n_left_from >= 8 && n_left_to_next >= 4)
2010 u32 bi0, bi1, bi2, bi3;
2011 vlib_buffer_t *b0, *b1, *b2, *b3;
2012 u32 next0, next1, next2, next3;
2013 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2014 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2015 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2016 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2017 u16 new_l0, new_l1, new_l2, new_l3;
2019 /* Prefetch next iteration. */
2021 vlib_buffer_t *p4, *p5, *p6, *p7;
2023 p4 = vlib_get_buffer (vm, from[4]);
2024 p5 = vlib_get_buffer (vm, from[5]);
2025 p6 = vlib_get_buffer (vm, from[6]);
2026 p7 = vlib_get_buffer (vm, from[7]);
2028 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2029 vlib_prefetch_buffer_header (p4, LOAD);
2030 vlib_prefetch_buffer_header (p5, LOAD);
2031 vlib_prefetch_buffer_header (p6, LOAD);
2032 vlib_prefetch_buffer_header (p7, LOAD);
2034 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2035 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2036 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2037 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2040 to_next[0] = bi0 = from[0];
2041 to_next[1] = bi1 = from[1];
2042 to_next[2] = bi2 = from[2];
2043 to_next[3] = bi3 = from[3];
2047 n_left_to_next -= 4;
2049 b0 = vlib_get_buffer (vm, bi0);
2050 b1 = vlib_get_buffer (vm, bi1);
2051 b2 = vlib_get_buffer (vm, bi2);
2052 b3 = vlib_get_buffer (vm, bi3);
2055 pool_elt_at_index (sm->sid_lists,
2056 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2058 pool_elt_at_index (sm->sid_lists,
2059 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2061 pool_elt_at_index (sm->sid_lists,
2062 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2064 pool_elt_at_index (sm->sid_lists,
2065 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2066 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2067 vec_len (sl0->rewrite));
2068 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2069 vec_len (sl1->rewrite));
2070 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2071 vec_len (sl2->rewrite));
2072 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2073 vec_len (sl3->rewrite));
2075 ip0 = vlib_buffer_get_current (b0);
2076 ip1 = vlib_buffer_get_current (b1);
2077 ip2 = vlib_buffer_get_current (b2);
2078 ip3 = vlib_buffer_get_current (b3);
2080 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2082 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2083 ip6_ext_header_len (ip0 + 1));
2085 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2087 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2089 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2090 ip6_ext_header_len (ip1 + 1));
2092 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2094 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2096 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2097 ip6_ext_header_len (ip2 + 1));
2099 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2101 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2103 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2104 ip6_ext_header_len (ip3 + 1));
2106 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2108 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2109 (void *) sr0 - (void *) ip0);
2110 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2111 (void *) sr1 - (void *) ip1);
2112 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2113 (void *) sr2 - (void *) ip2);
2114 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2115 (void *) sr3 - (void *) ip3);
2117 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2118 vec_len (sl0->rewrite));
2119 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2120 vec_len (sl1->rewrite));
2121 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2122 vec_len (sl2->rewrite));
2123 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2124 vec_len (sl3->rewrite));
2126 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2127 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2128 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2129 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2131 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2132 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2133 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2134 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2136 ip0->hop_limit -= 1;
2137 ip1->hop_limit -= 1;
2138 ip2->hop_limit -= 1;
2139 ip3->hop_limit -= 1;
2142 clib_net_to_host_u16 (ip0->payload_length) +
2143 vec_len (sl0->rewrite);
2145 clib_net_to_host_u16 (ip1->payload_length) +
2146 vec_len (sl1->rewrite);
2148 clib_net_to_host_u16 (ip2->payload_length) +
2149 vec_len (sl2->rewrite);
2151 clib_net_to_host_u16 (ip3->payload_length) +
2152 vec_len (sl3->rewrite);
2154 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2155 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2156 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2157 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2159 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2160 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2161 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2162 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2164 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2165 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2166 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2167 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2168 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2169 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2170 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2171 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2173 ip0->dst_address.as_u64[0] =
2174 (sr0->segments + sr0->segments_left)->as_u64[0];
2175 ip0->dst_address.as_u64[1] =
2176 (sr0->segments + sr0->segments_left)->as_u64[1];
2177 ip1->dst_address.as_u64[0] =
2178 (sr1->segments + sr1->segments_left)->as_u64[0];
2179 ip1->dst_address.as_u64[1] =
2180 (sr1->segments + sr1->segments_left)->as_u64[1];
2181 ip2->dst_address.as_u64[0] =
2182 (sr2->segments + sr2->segments_left)->as_u64[0];
2183 ip2->dst_address.as_u64[1] =
2184 (sr2->segments + sr2->segments_left)->as_u64[1];
2185 ip3->dst_address.as_u64[0] =
2186 (sr3->segments + sr3->segments_left)->as_u64[0];
2187 ip3->dst_address.as_u64[1] =
2188 (sr3->segments + sr3->segments_left)->as_u64[1];
2190 ip6_ext_header_t *ip_ext;
2191 if (ip0 + 1 == (void *) sr0)
2193 sr0->protocol = ip0->protocol;
2194 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2198 ip_ext = (void *) (ip0 + 1);
2199 sr0->protocol = ip_ext->next_hdr;
2200 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2203 if (ip1 + 1 == (void *) sr1)
2205 sr1->protocol = ip1->protocol;
2206 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2210 ip_ext = (void *) (ip2 + 1);
2211 sr2->protocol = ip_ext->next_hdr;
2212 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2215 if (ip2 + 1 == (void *) sr2)
2217 sr2->protocol = ip2->protocol;
2218 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2222 ip_ext = (void *) (ip2 + 1);
2223 sr2->protocol = ip_ext->next_hdr;
2224 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2227 if (ip3 + 1 == (void *) sr3)
2229 sr3->protocol = ip3->protocol;
2230 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2234 ip_ext = (void *) (ip3 + 1);
2235 sr3->protocol = ip_ext->next_hdr;
2236 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2241 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2243 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2245 sr_policy_rewrite_trace_t *tr =
2246 vlib_add_trace (vm, node, b0, sizeof (*tr));
2247 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2248 sizeof (tr->src.as_u8));
2249 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2250 sizeof (tr->dst.as_u8));
2253 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2255 sr_policy_rewrite_trace_t *tr =
2256 vlib_add_trace (vm, node, b1, sizeof (*tr));
2257 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2258 sizeof (tr->src.as_u8));
2259 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2260 sizeof (tr->dst.as_u8));
2263 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2265 sr_policy_rewrite_trace_t *tr =
2266 vlib_add_trace (vm, node, b2, sizeof (*tr));
2267 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2268 sizeof (tr->src.as_u8));
2269 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2270 sizeof (tr->dst.as_u8));
2273 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2275 sr_policy_rewrite_trace_t *tr =
2276 vlib_add_trace (vm, node, b3, sizeof (*tr));
2277 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2278 sizeof (tr->src.as_u8));
2279 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2280 sizeof (tr->dst.as_u8));
2284 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2285 n_left_to_next, bi0, bi1, bi2, bi3,
2286 next0, next1, next2, next3);
2289 /* Single loop for potentially the last three packets */
2290 while (n_left_from > 0 && n_left_to_next > 0)
2294 ip6_header_t *ip0 = 0;
2295 ip6_sr_header_t *sr0 = 0;
2297 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2305 n_left_to_next -= 1;
2307 b0 = vlib_get_buffer (vm, bi0);
2309 pool_elt_at_index (sm->sid_lists,
2310 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2311 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2312 vec_len (sl0->rewrite));
2314 ip0 = vlib_buffer_get_current (b0);
2316 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2318 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2319 ip6_ext_header_len (ip0 + 1));
2321 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2323 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2324 (void *) sr0 - (void *) ip0);
2325 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2326 vec_len (sl0->rewrite));
2328 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2330 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2331 ip0->hop_limit -= 1;
2333 clib_net_to_host_u16 (ip0->payload_length) +
2334 vec_len (sl0->rewrite);
2335 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2337 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2338 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2339 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2341 ip0->dst_address.as_u64[0] =
2342 (sr0->segments + sr0->segments_left)->as_u64[0];
2343 ip0->dst_address.as_u64[1] =
2344 (sr0->segments + sr0->segments_left)->as_u64[1];
2346 if (ip0 + 1 == (void *) sr0)
2348 sr0->protocol = ip0->protocol;
2349 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2353 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2354 sr0->protocol = ip_ext->next_hdr;
2355 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2358 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2359 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2361 sr_policy_rewrite_trace_t *tr =
2362 vlib_add_trace (vm, node, b0, sizeof (*tr));
2363 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2364 sizeof (tr->src.as_u8));
2365 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2366 sizeof (tr->dst.as_u8));
2371 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2372 n_left_to_next, bi0, next0);
2375 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2378 /* Update counters */
2379 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2380 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2382 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2383 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2385 return from_frame->n_vectors;
2389 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2390 .function = sr_policy_rewrite_insert,
2391 .name = "sr-pl-rewrite-insert",
2392 .vector_size = sizeof (u32),
2393 .format_trace = format_sr_policy_rewrite_trace,
2394 .type = VLIB_NODE_TYPE_INTERNAL,
2395 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2396 .error_strings = sr_policy_rewrite_error_strings,
2397 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2399 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2400 foreach_sr_policy_rewrite_next
2407 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2410 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2411 vlib_frame_t * from_frame)
2413 ip6_sr_main_t *sm = &sr_main;
2414 u32 n_left_from, next_index, *from, *to_next;
2416 from = vlib_frame_vector_args (from_frame);
2417 n_left_from = from_frame->n_vectors;
2419 next_index = node->cached_next_index;
2421 int insert_pkts = 0, bsid_pkts = 0;
2423 while (n_left_from > 0)
2427 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2430 while (n_left_from >= 8 && n_left_to_next >= 4)
2432 u32 bi0, bi1, bi2, bi3;
2433 vlib_buffer_t *b0, *b1, *b2, *b3;
2434 u32 next0, next1, next2, next3;
2435 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2436 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2437 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2438 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2439 u16 new_l0, new_l1, new_l2, new_l3;
2441 /* Prefetch next iteration. */
2443 vlib_buffer_t *p4, *p5, *p6, *p7;
2445 p4 = vlib_get_buffer (vm, from[4]);
2446 p5 = vlib_get_buffer (vm, from[5]);
2447 p6 = vlib_get_buffer (vm, from[6]);
2448 p7 = vlib_get_buffer (vm, from[7]);
2450 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2451 vlib_prefetch_buffer_header (p4, LOAD);
2452 vlib_prefetch_buffer_header (p5, LOAD);
2453 vlib_prefetch_buffer_header (p6, LOAD);
2454 vlib_prefetch_buffer_header (p7, LOAD);
2456 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2457 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2458 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2459 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2462 to_next[0] = bi0 = from[0];
2463 to_next[1] = bi1 = from[1];
2464 to_next[2] = bi2 = from[2];
2465 to_next[3] = bi3 = from[3];
2469 n_left_to_next -= 4;
2471 b0 = vlib_get_buffer (vm, bi0);
2472 b1 = vlib_get_buffer (vm, bi1);
2473 b2 = vlib_get_buffer (vm, bi2);
2474 b3 = vlib_get_buffer (vm, bi3);
2477 pool_elt_at_index (sm->sid_lists,
2478 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2480 pool_elt_at_index (sm->sid_lists,
2481 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2483 pool_elt_at_index (sm->sid_lists,
2484 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2486 pool_elt_at_index (sm->sid_lists,
2487 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2488 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2489 vec_len (sl0->rewrite_bsid));
2490 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2491 vec_len (sl1->rewrite_bsid));
2492 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2493 vec_len (sl2->rewrite_bsid));
2494 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2495 vec_len (sl3->rewrite_bsid));
2497 ip0 = vlib_buffer_get_current (b0);
2498 ip1 = vlib_buffer_get_current (b1);
2499 ip2 = vlib_buffer_get_current (b2);
2500 ip3 = vlib_buffer_get_current (b3);
2502 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2504 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2505 ip6_ext_header_len (ip0 + 1));
2507 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2509 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2511 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2512 ip6_ext_header_len (ip1 + 1));
2514 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2516 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2518 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2519 ip6_ext_header_len (ip2 + 1));
2521 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2523 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2525 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2526 ip6_ext_header_len (ip3 + 1));
2528 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2530 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2531 (void *) sr0 - (void *) ip0);
2532 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2533 (void *) sr1 - (void *) ip1);
2534 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2535 (void *) sr2 - (void *) ip2);
2536 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2537 (void *) sr3 - (void *) ip3);
2539 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2540 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2541 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2542 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2543 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2544 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2545 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2546 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2548 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2549 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2550 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2551 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2553 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2554 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2555 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2556 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2558 ip0->hop_limit -= 1;
2559 ip1->hop_limit -= 1;
2560 ip2->hop_limit -= 1;
2561 ip3->hop_limit -= 1;
2564 clib_net_to_host_u16 (ip0->payload_length) +
2565 vec_len (sl0->rewrite_bsid);
2567 clib_net_to_host_u16 (ip1->payload_length) +
2568 vec_len (sl1->rewrite_bsid);
2570 clib_net_to_host_u16 (ip2->payload_length) +
2571 vec_len (sl2->rewrite_bsid);
2573 clib_net_to_host_u16 (ip3->payload_length) +
2574 vec_len (sl3->rewrite_bsid);
2576 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2577 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2578 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2579 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2581 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2582 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2583 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2584 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2586 ip0->dst_address.as_u64[0] =
2587 (sr0->segments + sr0->segments_left)->as_u64[0];
2588 ip0->dst_address.as_u64[1] =
2589 (sr0->segments + sr0->segments_left)->as_u64[1];
2590 ip1->dst_address.as_u64[0] =
2591 (sr1->segments + sr1->segments_left)->as_u64[0];
2592 ip1->dst_address.as_u64[1] =
2593 (sr1->segments + sr1->segments_left)->as_u64[1];
2594 ip2->dst_address.as_u64[0] =
2595 (sr2->segments + sr2->segments_left)->as_u64[0];
2596 ip2->dst_address.as_u64[1] =
2597 (sr2->segments + sr2->segments_left)->as_u64[1];
2598 ip3->dst_address.as_u64[0] =
2599 (sr3->segments + sr3->segments_left)->as_u64[0];
2600 ip3->dst_address.as_u64[1] =
2601 (sr3->segments + sr3->segments_left)->as_u64[1];
2603 ip6_ext_header_t *ip_ext;
2604 if (ip0 + 1 == (void *) sr0)
2606 sr0->protocol = ip0->protocol;
2607 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2611 ip_ext = (void *) (ip0 + 1);
2612 sr0->protocol = ip_ext->next_hdr;
2613 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2616 if (ip1 + 1 == (void *) sr1)
2618 sr1->protocol = ip1->protocol;
2619 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2623 ip_ext = (void *) (ip2 + 1);
2624 sr2->protocol = ip_ext->next_hdr;
2625 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2628 if (ip2 + 1 == (void *) sr2)
2630 sr2->protocol = ip2->protocol;
2631 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2635 ip_ext = (void *) (ip2 + 1);
2636 sr2->protocol = ip_ext->next_hdr;
2637 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2640 if (ip3 + 1 == (void *) sr3)
2642 sr3->protocol = ip3->protocol;
2643 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2647 ip_ext = (void *) (ip3 + 1);
2648 sr3->protocol = ip_ext->next_hdr;
2649 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2654 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2656 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2658 sr_policy_rewrite_trace_t *tr =
2659 vlib_add_trace (vm, node, b0, sizeof (*tr));
2660 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2661 sizeof (tr->src.as_u8));
2662 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2663 sizeof (tr->dst.as_u8));
2666 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2668 sr_policy_rewrite_trace_t *tr =
2669 vlib_add_trace (vm, node, b1, sizeof (*tr));
2670 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2671 sizeof (tr->src.as_u8));
2672 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2673 sizeof (tr->dst.as_u8));
2676 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2678 sr_policy_rewrite_trace_t *tr =
2679 vlib_add_trace (vm, node, b2, sizeof (*tr));
2680 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2681 sizeof (tr->src.as_u8));
2682 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2683 sizeof (tr->dst.as_u8));
2686 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2688 sr_policy_rewrite_trace_t *tr =
2689 vlib_add_trace (vm, node, b3, sizeof (*tr));
2690 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2691 sizeof (tr->src.as_u8));
2692 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2693 sizeof (tr->dst.as_u8));
2697 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2698 n_left_to_next, bi0, bi1, bi2, bi3,
2699 next0, next1, next2, next3);
2702 /* Single loop for potentially the last three packets */
2703 while (n_left_from > 0 && n_left_to_next > 0)
2707 ip6_header_t *ip0 = 0;
2708 ip6_sr_header_t *sr0 = 0;
2710 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2718 n_left_to_next -= 1;
2720 b0 = vlib_get_buffer (vm, bi0);
2722 pool_elt_at_index (sm->sid_lists,
2723 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2724 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2725 vec_len (sl0->rewrite_bsid));
2727 ip0 = vlib_buffer_get_current (b0);
2729 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2731 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2732 ip6_ext_header_len (ip0 + 1));
2734 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2736 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2737 (void *) sr0 - (void *) ip0);
2738 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2739 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2741 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2743 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2744 ip0->hop_limit -= 1;
2746 clib_net_to_host_u16 (ip0->payload_length) +
2747 vec_len (sl0->rewrite_bsid);
2748 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2750 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2752 ip0->dst_address.as_u64[0] =
2753 (sr0->segments + sr0->segments_left)->as_u64[0];
2754 ip0->dst_address.as_u64[1] =
2755 (sr0->segments + sr0->segments_left)->as_u64[1];
2757 if (ip0 + 1 == (void *) sr0)
2759 sr0->protocol = ip0->protocol;
2760 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2764 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2765 sr0->protocol = ip_ext->next_hdr;
2766 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2769 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2770 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2772 sr_policy_rewrite_trace_t *tr =
2773 vlib_add_trace (vm, node, b0, sizeof (*tr));
2774 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2775 sizeof (tr->src.as_u8));
2776 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2777 sizeof (tr->dst.as_u8));
2782 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2783 n_left_to_next, bi0, next0);
2786 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2789 /* Update counters */
2790 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2791 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2793 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2794 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2796 return from_frame->n_vectors;
2800 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2801 .function = sr_policy_rewrite_b_insert,
2802 .name = "sr-pl-rewrite-b-insert",
2803 .vector_size = sizeof (u32),
2804 .format_trace = format_sr_policy_rewrite_trace,
2805 .type = VLIB_NODE_TYPE_INTERNAL,
2806 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2807 .error_strings = sr_policy_rewrite_error_strings,
2808 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2810 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2811 foreach_sr_policy_rewrite_next
2818 * @brief Function BSID encapsulation
2820 static_always_inline void
2821 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2824 ip6_sr_header_t * sr0, u32 * next0)
2826 ip6_address_t *new_dst0;
2828 if (PREDICT_FALSE (!sr0))
2829 goto error_bsid_encaps;
2831 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2833 if (PREDICT_TRUE (sr0->segments_left != 0))
2835 sr0->segments_left -= 1;
2836 new_dst0 = (ip6_address_t *) (sr0->segments);
2837 new_dst0 += sr0->segments_left;
2838 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2839 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2845 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2846 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2850 * @brief Graph node for applying a SR policy BSID - Encapsulation
2853 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2854 vlib_frame_t * from_frame)
2856 ip6_sr_main_t *sm = &sr_main;
2857 u32 n_left_from, next_index, *from, *to_next;
2859 from = vlib_frame_vector_args (from_frame);
2860 n_left_from = from_frame->n_vectors;
2862 next_index = node->cached_next_index;
2864 int encap_pkts = 0, bsid_pkts = 0;
2866 while (n_left_from > 0)
2870 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2873 while (n_left_from >= 8 && n_left_to_next >= 4)
2875 u32 bi0, bi1, bi2, bi3;
2876 vlib_buffer_t *b0, *b1, *b2, *b3;
2877 u32 next0, next1, next2, next3;
2878 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2879 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2880 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2881 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2882 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2883 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2885 /* Prefetch next iteration. */
2887 vlib_buffer_t *p4, *p5, *p6, *p7;
2889 p4 = vlib_get_buffer (vm, from[4]);
2890 p5 = vlib_get_buffer (vm, from[5]);
2891 p6 = vlib_get_buffer (vm, from[6]);
2892 p7 = vlib_get_buffer (vm, from[7]);
2894 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2895 vlib_prefetch_buffer_header (p4, LOAD);
2896 vlib_prefetch_buffer_header (p5, LOAD);
2897 vlib_prefetch_buffer_header (p6, LOAD);
2898 vlib_prefetch_buffer_header (p7, LOAD);
2900 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2901 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2902 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2903 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2906 to_next[0] = bi0 = from[0];
2907 to_next[1] = bi1 = from[1];
2908 to_next[2] = bi2 = from[2];
2909 to_next[3] = bi3 = from[3];
2913 n_left_to_next -= 4;
2915 b0 = vlib_get_buffer (vm, bi0);
2916 b1 = vlib_get_buffer (vm, bi1);
2917 b2 = vlib_get_buffer (vm, bi2);
2918 b3 = vlib_get_buffer (vm, bi3);
2921 pool_elt_at_index (sm->sid_lists,
2922 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2924 pool_elt_at_index (sm->sid_lists,
2925 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2927 pool_elt_at_index (sm->sid_lists,
2928 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2930 pool_elt_at_index (sm->sid_lists,
2931 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2932 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2933 vec_len (sl0->rewrite));
2934 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2935 vec_len (sl1->rewrite));
2936 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2937 vec_len (sl2->rewrite));
2938 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2939 vec_len (sl3->rewrite));
2941 ip0_encap = vlib_buffer_get_current (b0);
2942 ip1_encap = vlib_buffer_get_current (b1);
2943 ip2_encap = vlib_buffer_get_current (b2);
2944 ip3_encap = vlib_buffer_get_current (b3);
2946 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2947 IP_PROTOCOL_IPV6_ROUTE);
2948 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2949 IP_PROTOCOL_IPV6_ROUTE);
2950 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2951 IP_PROTOCOL_IPV6_ROUTE);
2952 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2953 IP_PROTOCOL_IPV6_ROUTE);
2955 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2956 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2957 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2958 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2960 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2961 sl0->rewrite, vec_len (sl0->rewrite));
2962 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2963 sl1->rewrite, vec_len (sl1->rewrite));
2964 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2965 sl2->rewrite, vec_len (sl2->rewrite));
2966 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2967 sl3->rewrite, vec_len (sl3->rewrite));
2969 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2970 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2971 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2972 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2974 ip0 = vlib_buffer_get_current (b0);
2975 ip1 = vlib_buffer_get_current (b1);
2976 ip2 = vlib_buffer_get_current (b2);
2977 ip3 = vlib_buffer_get_current (b3);
2979 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2980 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2981 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2982 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2984 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2986 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2988 sr_policy_rewrite_trace_t *tr =
2989 vlib_add_trace (vm, node, b0, sizeof (*tr));
2990 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2991 sizeof (tr->src.as_u8));
2992 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2993 sizeof (tr->dst.as_u8));
2996 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2998 sr_policy_rewrite_trace_t *tr =
2999 vlib_add_trace (vm, node, b1, sizeof (*tr));
3000 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3001 sizeof (tr->src.as_u8));
3002 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3003 sizeof (tr->dst.as_u8));
3006 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3008 sr_policy_rewrite_trace_t *tr =
3009 vlib_add_trace (vm, node, b2, sizeof (*tr));
3010 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3011 sizeof (tr->src.as_u8));
3012 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3013 sizeof (tr->dst.as_u8));
3016 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3018 sr_policy_rewrite_trace_t *tr =
3019 vlib_add_trace (vm, node, b3, sizeof (*tr));
3020 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3021 sizeof (tr->src.as_u8));
3022 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3023 sizeof (tr->dst.as_u8));
3028 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3029 n_left_to_next, bi0, bi1, bi2, bi3,
3030 next0, next1, next2, next3);
3033 /* Single loop for potentially the last three packets */
3034 while (n_left_from > 0 && n_left_to_next > 0)
3038 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3039 ip6_ext_header_t *prev0;
3040 ip6_sr_header_t *sr0;
3042 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3049 n_left_to_next -= 1;
3050 b0 = vlib_get_buffer (vm, bi0);
3053 pool_elt_at_index (sm->sid_lists,
3054 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3055 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3056 vec_len (sl0->rewrite));
3058 ip0_encap = vlib_buffer_get_current (b0);
3059 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3060 IP_PROTOCOL_IPV6_ROUTE);
3061 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3063 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3064 sl0->rewrite, vec_len (sl0->rewrite));
3065 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3067 ip0 = vlib_buffer_get_current (b0);
3069 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3071 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3072 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3074 sr_policy_rewrite_trace_t *tr =
3075 vlib_add_trace (vm, node, b0, sizeof (*tr));
3076 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3077 sizeof (tr->src.as_u8));
3078 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3079 sizeof (tr->dst.as_u8));
3083 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3084 n_left_to_next, bi0, next0);
3087 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3090 /* Update counters */
3091 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3092 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3094 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3095 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3098 return from_frame->n_vectors;
3102 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3103 .function = sr_policy_rewrite_b_encaps,
3104 .name = "sr-pl-rewrite-b-encaps",
3105 .vector_size = sizeof (u32),
3106 .format_trace = format_sr_policy_rewrite_trace,
3107 .type = VLIB_NODE_TYPE_INTERNAL,
3108 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3109 .error_strings = sr_policy_rewrite_error_strings,
3110 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3112 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3113 foreach_sr_policy_rewrite_next
3119 /*************************** SR Segment Lists DPOs ****************************/
3121 format_sr_segment_list_dpo (u8 * s, va_list * args)
3123 ip6_sr_main_t *sm = &sr_main;
3124 ip6_address_t *addr;
3127 index_t index = va_arg (*args, index_t);
3128 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3129 s = format (s, "SR: Segment List index:[%d]", index);
3130 s = format (s, "\n\tSegments:");
3132 sl = pool_elt_at_index (sm->sid_lists, index);
3134 s = format (s, "< ");
3135 vec_foreach (addr, sl->segments)
3137 s = format (s, "%U, ", format_ip6_address, addr);
3139 s = format (s, "\b\b > - ");
3140 s = format (s, "Weight: %u", sl->weight);
3145 const static dpo_vft_t sr_policy_rewrite_vft = {
3146 .dv_lock = sr_dpo_lock,
3147 .dv_unlock = sr_dpo_unlock,
3148 .dv_format = format_sr_segment_list_dpo,
3151 const static char *const sr_pr_encaps_ip6_nodes[] = {
3152 "sr-pl-rewrite-encaps",
3156 const static char *const sr_pr_encaps_ip4_nodes[] = {
3157 "sr-pl-rewrite-encaps-v4",
3161 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3162 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3163 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3166 const static char *const sr_pr_insert_ip6_nodes[] = {
3167 "sr-pl-rewrite-insert",
3171 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3172 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3175 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3176 "sr-pl-rewrite-b-insert",
3180 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3181 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3184 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3185 "sr-pl-rewrite-b-encaps",
3189 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3190 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3193 /********************* SR Policy Rewrite initialization ***********************/
3195 * @brief SR Policy Rewrite initialization
3198 sr_policy_rewrite_init (vlib_main_t * vm)
3200 ip6_sr_main_t *sm = &sr_main;
3202 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3203 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3204 sizeof (ip6_address_t));
3206 /* Init SR VPO DPOs type */
3207 sr_pr_encaps_dpo_type =
3208 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3210 sr_pr_insert_dpo_type =
3211 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3213 sr_pr_bsid_encaps_dpo_type =
3214 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3216 sr_pr_bsid_insert_dpo_type =
3217 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3219 /* Register the L2 encaps node used in HW redirect */
3220 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3222 sm->fib_table_ip6 = (u32) ~ 0;
3223 sm->fib_table_ip4 = (u32) ~ 0;
3228 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3232 * fd.io coding-style-patch-verification: ON
3235 * eval: (c-set-style "gnu")