2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
115 static clib_error_t *
116 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
125 return clib_error_return (0, "No address specified");
127 return clib_error_return (0, "No address specified");
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132 .path = "set sr encaps source",
133 .short_help = "set sr encaps source addr <ip6_addr>",
134 .function = set_sr_src_command_fn,
138 /*********************** SR rewrite string computation ************************/
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
142 * @param sl is a vector of IPv6 addresses composing the Segment List
144 * @return precomputed rewrite string for encapsulation
147 compute_rewrite_encaps (ip6_address_t * sl)
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
163 vec_validate (rs, header_length - 1);
165 iph = (ip6_header_t *) rs;
166 iph->ip_version_traffic_class_and_flow_label =
167 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171 iph->protocol = IP_PROTOCOL_IPV6;
172 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
174 srh = (ip6_sr_header_t *) (iph + 1);
175 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176 srh->protocol = IP_PROTOCOL_IPV6;
177 srh->type = ROUTING_HEADER_TYPE_SR;
178 srh->segments_left = vec_len (sl) - 1;
179 srh->first_segment = vec_len (sl) - 1;
180 srh->length = ((sizeof (ip6_sr_header_t) +
181 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
196 * @brief SR rewrite string computation for SRH insertion (inline)
198 * @param sl is a vector of IPv6 addresses composing the Segment List
200 * @return precomputed rewrite string for SRH insertion
203 compute_rewrite_insert (ip6_address_t * sl)
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 srh = (ip6_sr_header_t *) rs;
217 srh->type = ROUTING_HEADER_TYPE_SR;
218 srh->segments_left = vec_len (sl);
219 srh->first_segment = vec_len (sl);
220 srh->length = ((sizeof (ip6_sr_header_t) +
221 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
236 * @param sl is a vector of IPv6 addresses composing the Segment List
238 * @return precomputed rewrite string for SRH insertion with BSID
241 compute_rewrite_bsid (ip6_address_t * sl)
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
252 vec_validate (rs, header_length - 1);
254 srh = (ip6_sr_header_t *) rs;
255 srh->type = ROUTING_HEADER_TYPE_SR;
256 srh->segments_left = vec_len (sl) - 1;
257 srh->first_segment = vec_len (sl) - 1;
258 srh->length = ((sizeof (ip6_sr_header_t) +
259 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
271 /*************************** SR LB helper functions **************************/
273 * @brief Creates a Segment List and adds it to an SR policy
275 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276 * not necessarily unique. Hence there might be two Segment List within the
277 * same SR Policy with exactly the same segments and same weight.
279 * @param sr_policy is the SR policy where the SL will be added
280 * @param sl is a vector of IPv6 addresses composing the Segment List
281 * @param weight is the weight of the SegmentList (for load-balancing purposes)
282 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
284 * @return pointer to the just created segment list
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
298 /* Fill in segment list */
299 segment_list->weight =
300 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301 segment_list->segments = vec_dup (sl);
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
321 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
322 segment_list - sm->sid_lists);
323 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
324 segment_list - sm->sid_lists);
325 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
326 DPO_PROTO_IP6, segment_list - sm->sid_lists);
330 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
331 segment_list - sm->sid_lists);
332 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
333 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 * @brief Updates the Load Balancer after an SR Policy change
342 * @param sr_policy is the modified SR Policy
345 update_lb (ip6_sr_policy_t * sr_policy)
347 flow_hash_config_t fhc;
349 ip6_sr_sl_t *segment_list;
350 ip6_sr_main_t *sm = &sr_main;
351 load_balance_path_t path;
352 path.path_index = FIB_NODE_INDEX_INVALID;
353 load_balance_path_t *ip4_path_vector = 0;
354 load_balance_path_t *ip6_path_vector = 0;
355 load_balance_path_t *b_path_vector = 0;
357 /* In case LB does not exist, create it */
358 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
361 .fp_proto = FIB_PROTOCOL_IP6,
364 .ip6 = sr_policy->bsid,
368 /* Add FIB entry for BSID */
369 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
370 dpo_proto_to_fib (DPO_PROTO_IP6));
372 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
373 load_balance_create (0, DPO_PROTO_IP6, fhc));
375 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
376 load_balance_create (0, DPO_PROTO_IP6, fhc));
378 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
379 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
380 sr_policy->fib_table),
382 FIB_ENTRY_FLAG_EXCLUSIVE,
383 &sr_policy->bsid_dpo);
385 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->ip6_dpo);
391 if (sr_policy->is_encap)
393 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
394 load_balance_create (0, DPO_PROTO_IP4, fhc));
396 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
399 FIB_ENTRY_FLAG_EXCLUSIVE,
400 &sr_policy->ip4_dpo);
405 /* Create the LB path vector */
406 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
407 vec_foreach (sl_index, sr_policy->segments_lists)
409 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
410 path.path_dpo = segment_list->bsid_dpo;
411 path.path_weight = segment_list->weight;
412 vec_add1 (b_path_vector, path);
413 path.path_dpo = segment_list->ip6_dpo;
414 vec_add1 (ip6_path_vector, path);
415 if (sr_policy->is_encap)
417 path.path_dpo = segment_list->ip4_dpo;
418 vec_add1 (ip4_path_vector, path);
422 /* Update LB multipath */
423 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
424 LOAD_BALANCE_FLAG_NONE);
425 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
426 LOAD_BALANCE_FLAG_NONE);
427 if (sr_policy->is_encap)
428 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
429 LOAD_BALANCE_FLAG_NONE);
432 vec_free (b_path_vector);
433 vec_free (ip6_path_vector);
434 vec_free (ip4_path_vector);
439 * @brief Updates the Replicate DPO after an SR Policy change
441 * @param sr_policy is the modified SR Policy (type spray)
444 update_replicate (ip6_sr_policy_t * sr_policy)
447 ip6_sr_sl_t *segment_list;
448 ip6_sr_main_t *sm = &sr_main;
449 load_balance_path_t path;
450 path.path_index = FIB_NODE_INDEX_INVALID;
451 load_balance_path_t *b_path_vector = 0;
452 load_balance_path_t *ip6_path_vector = 0;
453 load_balance_path_t *ip4_path_vector = 0;
455 /* In case LB does not exist, create it */
456 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
458 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
459 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
461 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
462 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
464 /* Update FIB entry's DPO to point to SR without LB */
466 .fp_proto = FIB_PROTOCOL_IP6,
469 .ip6 = sr_policy->bsid,
472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
484 if (sr_policy->is_encap)
486 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
487 replicate_create (0, DPO_PROTO_IP4));
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
498 /* Create the replicate path vector */
499 path.path_weight = 1;
500 vec_foreach (sl_index, sr_policy->segments_lists)
502 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
503 path.path_dpo = segment_list->bsid_dpo;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
514 /* Update replicate multipath */
515 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
516 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
517 if (sr_policy->is_encap)
518 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
521 /******************************* SR rewrite API *******************************/
522 /* Three functions for handling sr policies:
526 * All of them are API. CLI function on sr_policy_command_fn */
529 * @brief Create a new SR policy
531 * @param bsid is the bindingSID of the SR Policy
532 * @param segments is a vector of IPv6 address composing the segment list
533 * @param weight is the weight of the sid list. optional.
534 * @param behavior is the behavior of the SR policy. (default//spray)
535 * @param fib_table is the VRF where to install the FIB entry for the BSID
536 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
538 * @return 0 if correct, else error
541 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
542 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
544 ip6_sr_main_t *sm = &sr_main;
545 ip6_sr_policy_t *sr_policy = 0;
548 /* Search for existing keys (BSID) */
549 p = mhash_get (&sm->sr_policies_index_hash, bsid);
552 /* Add SR policy that already exists; complain */
556 /* Search collision in FIB entries */
557 /* Explanation: It might be possible that some other entity has already
558 * created a route for the BSID. This in theory is impossible, but in
559 * practise we could see it. Assert it and scream if needed */
561 .fp_proto = FIB_PROTOCOL_IP6,
568 /* Lookup the FIB index associated to the table selected */
569 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
570 (fib_table != (u32) ~ 0 ? fib_table : 0));
574 /* Lookup whether there exists an entry for the BSID */
575 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
576 if (FIB_NODE_INDEX_INVALID != fei)
577 return -12; //There is an entry for such lookup
579 /* Add an SR policy object */
580 pool_get (sm->sr_policies, sr_policy);
581 memset (sr_policy, 0, sizeof (*sr_policy));
582 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
583 sr_policy->type = behavior;
584 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
585 sr_policy->is_encap = is_encap;
588 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
591 /* Create a segment list and add the index to the SR policy */
592 create_sl (sr_policy, segments, weight, is_encap);
594 /* If FIB doesnt exist, create them */
595 if (sm->fib_table_ip6 == (u32) ~ 0)
597 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
599 "SRv6 steering of IP6 prefixes through BSIDs");
600 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
602 "SRv6 steering of IP4 prefixes through BSIDs");
605 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
606 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
607 update_lb (sr_policy);
608 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
609 update_replicate (sr_policy);
614 * @brief Delete a SR policy
616 * @param bsid is the bindingSID of the SR Policy
617 * @param index is the index of the SR policy
619 * @return 0 if correct, else error
622 sr_policy_del (ip6_address_t * bsid, u32 index)
624 ip6_sr_main_t *sm = &sr_main;
625 ip6_sr_policy_t *sr_policy = 0;
626 ip6_sr_sl_t *segment_list;
632 p = mhash_get (&sm->sr_policies_index_hash, bsid);
634 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
640 sr_policy = pool_elt_at_index (sm->sr_policies, index);
645 /* Remove BindingSID FIB entry */
647 .fp_proto = FIB_PROTOCOL_IP6,
650 .ip6 = sr_policy->bsid,
655 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
656 sr_policy->fib_table),
657 &pfx, FIB_SOURCE_SR);
659 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
661 if (sr_policy->is_encap)
662 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
664 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
666 dpo_reset (&sr_policy->bsid_dpo);
667 dpo_reset (&sr_policy->ip4_dpo);
668 dpo_reset (&sr_policy->ip6_dpo);
671 /* Clean SID Lists */
672 vec_foreach (sl_index, sr_policy->segments_lists)
674 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
675 vec_free (segment_list->segments);
676 vec_free (segment_list->rewrite);
677 if (!sr_policy->is_encap)
678 vec_free (segment_list->rewrite_bsid);
679 pool_put_index (sm->sid_lists, *sl_index);
682 /* Remove SR policy entry */
683 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
684 pool_put (sm->sr_policies, sr_policy);
686 /* If FIB empty unlock it */
687 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
689 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
690 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
691 sm->fib_table_ip6 = (u32) ~ 0;
692 sm->fib_table_ip4 = (u32) ~ 0;
699 * @brief Modify an existing SR policy
701 * The possible modifications are adding a new Segment List, modifying an
702 * existing Segment List (modify the weight only) and delete a given
703 * Segment List from the SR Policy.
705 * @param bsid is the bindingSID of the SR Policy
706 * @param index is the index of the SR policy
707 * @param fib_table is the VRF where to install the FIB entry for the BSID
708 * @param operation is the operation to perform (among the top ones)
709 * @param segments is a vector of IPv6 address composing the segment list
710 * @param sl_index is the index of the Segment List to modify/delete
711 * @param weight is the weight of the sid list. optional.
712 * @param is_encap Mode. Encapsulation or SRH insertion.
714 * @return 0 if correct, else error
717 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
718 u8 operation, ip6_address_t * segments, u32 sl_index,
721 ip6_sr_main_t *sm = &sr_main;
722 ip6_sr_policy_t *sr_policy = 0;
723 ip6_sr_sl_t *segment_list;
724 u32 *sl_index_iterate;
729 p = mhash_get (&sm->sr_policies_index_hash, bsid);
731 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
737 sr_policy = pool_elt_at_index (sm->sr_policies, index);
742 if (operation == 1) /* Add SR List to an existing SR policy */
744 /* Create the new SL */
746 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
748 /* Create a new LB DPO */
749 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
750 update_lb (sr_policy);
751 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
752 update_replicate (sr_policy);
754 else if (operation == 2) /* Delete SR List from an existing SR policy */
756 /* Check that currently there are more than one SID list */
757 if (vec_len (sr_policy->segments_lists) == 1)
760 /* Check that the SR list does exist and is assigned to the sr policy */
761 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
762 if (*sl_index_iterate == sl_index)
765 if (*sl_index_iterate != sl_index)
768 /* Remove the lucky SR list that is being kicked out */
769 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
770 vec_free (segment_list->segments);
771 vec_free (segment_list->rewrite);
772 if (!sr_policy->is_encap)
773 vec_free (segment_list->rewrite_bsid);
774 pool_put_index (sm->sid_lists, sl_index);
775 vec_del1 (sr_policy->segments_lists,
776 sl_index_iterate - sr_policy->segments_lists);
778 /* Create a new LB DPO */
779 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
780 update_lb (sr_policy);
781 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
782 update_replicate (sr_policy);
784 else if (operation == 3) /* Modify the weight of an existing SR List */
786 /* Find the corresponding SL */
787 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
788 if (*sl_index_iterate == sl_index)
791 if (*sl_index_iterate != sl_index)
794 /* Change the weight */
795 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
796 segment_list->weight = weight;
799 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
800 update_lb (sr_policy);
802 else /* Incorrect op. */
809 * @brief CLI for 'sr policies' command family
811 static clib_error_t *
812 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
813 vlib_cli_command_t * cmd)
816 char is_del = 0, is_add = 0, is_mod = 0;
818 ip6_address_t bsid, next_address;
819 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
820 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
821 ip6_address_t *segments = 0, *this_seg;
826 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
828 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
830 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
832 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
835 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
837 else if (!is_add && !policy_set
838 && unformat (input, "index %d", &sr_policy_index))
840 else if (unformat (input, "weight %d", &weight));
842 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
844 vec_add2 (segments, this_seg, 1);
845 clib_memcpy (this_seg->as_u8, next_address.as_u8,
848 else if (unformat (input, "add sl"))
850 else if (unformat (input, "del sl index %d", &sl_index))
852 else if (unformat (input, "mod sl index %d", &sl_index))
854 else if (fib_table == (u32) ~ 0
855 && unformat (input, "fib-table %d", &fib_table));
856 else if (unformat (input, "encap"))
858 else if (unformat (input, "insert"))
860 else if (unformat (input, "spray"))
866 if (!is_add && !is_mod && !is_del)
867 return clib_error_return (0, "Incorrect CLI");
870 return clib_error_return (0, "No SR policy BSID or index specified");
874 if (vec_len (segments) == 0)
875 return clib_error_return (0, "No Segment List specified");
876 rv = sr_policy_add (&bsid, segments, weight,
877 (is_spray ? SR_POLICY_TYPE_SPRAY :
878 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
881 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
886 return clib_error_return (0, "No SL modification specified");
887 if (operation != 1 && sl_index == (u32) ~ 0)
888 return clib_error_return (0, "No Segment List index specified");
889 if (operation == 1 && vec_len (segments) == 0)
890 return clib_error_return (0, "No Segment List specified");
891 if (operation == 3 && weight == (u32) ~ 0)
892 return clib_error_return (0, "No new weight for the SL specified");
893 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
894 sr_policy_index, fib_table, operation, segments,
905 return clib_error_return (0,
906 "There is already a FIB entry for the BindingSID address.\n"
907 "The SR policy could not be created.");
909 return clib_error_return (0, "The specified FIB table does not exist.");
911 return clib_error_return (0,
912 "The selected SR policy only contains ONE segment list. "
913 "Please remove the SR policy instead");
915 return clib_error_return (0,
916 "Could not delete the segment list. "
917 "It is not associated with that SR policy.");
919 return clib_error_return (0,
920 "Could not modify the segment list. "
921 "The given SL is not associated with such SR policy.");
923 return clib_error_return (0, "BUG: sr policy returns %d", rv);
929 VLIB_CLI_COMMAND (sr_policy_command, static) = {
931 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
932 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
934 "Manipulation of SR policies.\n"
935 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
936 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
937 "Segment Routing policies might be of type encapsulation or srh insertion\n"
938 "Each SR policy will be associated with a unique BindingSID.\n"
939 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
940 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
941 "The add command will create a SR policy with its first segment list (sl)\n"
942 "The mod command allows you to add, remove, or modify the existing segment lists\n"
943 "within an SR policy.\n"
944 "The del command allows you to delete a SR policy along with all its associated\n"
946 .function = sr_policy_command_fn,
951 * @brief CLI to display onscreen all the SR policies
953 static clib_error_t *
954 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
955 vlib_cli_command_t * cmd)
957 ip6_sr_main_t *sm = &sr_main;
959 ip6_sr_sl_t *segment_list = 0;
960 ip6_sr_policy_t *sr_policy = 0;
961 ip6_sr_policy_t **vec_policies = 0;
966 vlib_cli_output (vm, "SR policies:");
969 pool_foreach (sr_policy, sm->sr_policies,
970 {vec_add1 (vec_policies, sr_policy); } );
973 vec_foreach_index (i, vec_policies)
975 sr_policy = vec_policies[i];
976 vlib_cli_output (vm, "[%u].-\tBSID: %U",
977 (u32) (sr_policy - sm->sr_policies),
978 format_ip6_address, &sr_policy->bsid);
979 vlib_cli_output (vm, "\tBehavior: %s",
980 (sr_policy->is_encap ? "Encapsulation" :
982 vlib_cli_output (vm, "\tType: %s",
984 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
985 vlib_cli_output (vm, "\tFIB table: %u",
986 (sr_policy->fib_table !=
987 (u32) ~ 0 ? sr_policy->fib_table : 0));
988 vlib_cli_output (vm, "\tSegment Lists:");
989 vec_foreach (sl_index, sr_policy->segments_lists)
992 s = format (s, "\t[%u].- ", *sl_index);
993 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
994 s = format (s, "< ");
995 vec_foreach (addr, segment_list->segments)
997 s = format (s, "%U, ", format_ip6_address, addr);
999 s = format (s, "\b\b > ");
1000 s = format (s, "weight: %u", segment_list->weight);
1001 vlib_cli_output (vm, " %s", s);
1003 vlib_cli_output (vm, "-----------");
1009 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1010 .path = "show sr policies",
1011 .short_help = "show sr policies",
1012 .function = show_sr_policies_command_fn,
1016 /*************************** SR rewrite graph node ****************************/
1018 * @brief Trace for the SR Policy Rewrite graph node
1021 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1024 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1025 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1026 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1029 (s, "SR-policy-rewrite: src %U dst %U",
1030 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1036 * @brief IPv6 encapsulation processing as per RFC2473
1038 static_always_inline void
1039 encaps_processing_v6 (vlib_node_runtime_t * node,
1041 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1045 ip0_encap->hop_limit -= 1;
1047 ip0->payload_length + sizeof (ip6_header_t) +
1048 clib_net_to_host_u16 (ip0_encap->payload_length);
1049 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1050 ip0->ip_version_traffic_class_and_flow_label =
1051 ip0_encap->ip_version_traffic_class_and_flow_label;
1055 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1058 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1059 vlib_frame_t * from_frame)
1061 ip6_sr_main_t *sm = &sr_main;
1062 u32 n_left_from, next_index, *from, *to_next;
1064 from = vlib_frame_vector_args (from_frame);
1065 n_left_from = from_frame->n_vectors;
1067 next_index = node->cached_next_index;
1069 int encap_pkts = 0, bsid_pkts = 0;
1071 while (n_left_from > 0)
1075 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1078 while (n_left_from >= 8 && n_left_to_next >= 4)
1080 u32 bi0, bi1, bi2, bi3;
1081 vlib_buffer_t *b0, *b1, *b2, *b3;
1082 u32 next0, next1, next2, next3;
1083 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1084 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1085 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1086 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1088 /* Prefetch next iteration. */
1090 vlib_buffer_t *p4, *p5, *p6, *p7;
1092 p4 = vlib_get_buffer (vm, from[4]);
1093 p5 = vlib_get_buffer (vm, from[5]);
1094 p6 = vlib_get_buffer (vm, from[6]);
1095 p7 = vlib_get_buffer (vm, from[7]);
1097 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1098 vlib_prefetch_buffer_header (p4, LOAD);
1099 vlib_prefetch_buffer_header (p5, LOAD);
1100 vlib_prefetch_buffer_header (p6, LOAD);
1101 vlib_prefetch_buffer_header (p7, LOAD);
1103 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1104 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1105 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1106 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1109 to_next[0] = bi0 = from[0];
1110 to_next[1] = bi1 = from[1];
1111 to_next[2] = bi2 = from[2];
1112 to_next[3] = bi3 = from[3];
1116 n_left_to_next -= 4;
1118 b0 = vlib_get_buffer (vm, bi0);
1119 b1 = vlib_get_buffer (vm, bi1);
1120 b2 = vlib_get_buffer (vm, bi2);
1121 b3 = vlib_get_buffer (vm, bi3);
1124 pool_elt_at_index (sm->sid_lists,
1125 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1127 pool_elt_at_index (sm->sid_lists,
1128 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1130 pool_elt_at_index (sm->sid_lists,
1131 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1133 pool_elt_at_index (sm->sid_lists,
1134 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1136 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1137 vec_len (sl0->rewrite));
1138 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1139 vec_len (sl1->rewrite));
1140 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1141 vec_len (sl2->rewrite));
1142 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1143 vec_len (sl3->rewrite));
1145 ip0_encap = vlib_buffer_get_current (b0);
1146 ip1_encap = vlib_buffer_get_current (b1);
1147 ip2_encap = vlib_buffer_get_current (b2);
1148 ip3_encap = vlib_buffer_get_current (b3);
1150 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1151 sl0->rewrite, vec_len (sl0->rewrite));
1152 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1153 sl1->rewrite, vec_len (sl1->rewrite));
1154 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1155 sl2->rewrite, vec_len (sl2->rewrite));
1156 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1157 sl3->rewrite, vec_len (sl3->rewrite));
1159 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1160 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1161 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1162 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1164 ip0 = vlib_buffer_get_current (b0);
1165 ip1 = vlib_buffer_get_current (b1);
1166 ip2 = vlib_buffer_get_current (b2);
1167 ip3 = vlib_buffer_get_current (b3);
1169 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1170 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1171 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1172 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1174 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1176 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1178 sr_policy_rewrite_trace_t *tr =
1179 vlib_add_trace (vm, node, b0, sizeof (*tr));
1180 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1181 sizeof (tr->src.as_u8));
1182 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1183 sizeof (tr->dst.as_u8));
1186 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1188 sr_policy_rewrite_trace_t *tr =
1189 vlib_add_trace (vm, node, b1, sizeof (*tr));
1190 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1191 sizeof (tr->src.as_u8));
1192 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1193 sizeof (tr->dst.as_u8));
1196 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1198 sr_policy_rewrite_trace_t *tr =
1199 vlib_add_trace (vm, node, b2, sizeof (*tr));
1200 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1201 sizeof (tr->src.as_u8));
1202 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1203 sizeof (tr->dst.as_u8));
1206 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1208 sr_policy_rewrite_trace_t *tr =
1209 vlib_add_trace (vm, node, b3, sizeof (*tr));
1210 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1211 sizeof (tr->src.as_u8));
1212 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1213 sizeof (tr->dst.as_u8));
1218 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1219 n_left_to_next, bi0, bi1, bi2, bi3,
1220 next0, next1, next2, next3);
1223 /* Single loop for potentially the last three packets */
1224 while (n_left_from > 0 && n_left_to_next > 0)
1228 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1230 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1237 n_left_to_next -= 1;
1238 b0 = vlib_get_buffer (vm, bi0);
1241 pool_elt_at_index (sm->sid_lists,
1242 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1244 vec_len (sl0->rewrite));
1246 ip0_encap = vlib_buffer_get_current (b0);
1248 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1249 sl0->rewrite, vec_len (sl0->rewrite));
1250 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1252 ip0 = vlib_buffer_get_current (b0);
1254 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1256 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1257 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1259 sr_policy_rewrite_trace_t *tr =
1260 vlib_add_trace (vm, node, b0, sizeof (*tr));
1261 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1262 sizeof (tr->src.as_u8));
1263 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1264 sizeof (tr->dst.as_u8));
1268 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1269 n_left_to_next, bi0, next0);
1272 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1275 /* Update counters */
1276 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1277 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1279 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1280 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1283 return from_frame->n_vectors;
1287 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1288 .function = sr_policy_rewrite_encaps,
1289 .name = "sr-pl-rewrite-encaps",
1290 .vector_size = sizeof (u32),
1291 .format_trace = format_sr_policy_rewrite_trace,
1292 .type = VLIB_NODE_TYPE_INTERNAL,
1293 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1294 .error_strings = sr_policy_rewrite_error_strings,
1295 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1297 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1298 foreach_sr_policy_rewrite_next
1305 * @brief IPv4 encapsulation processing as per RFC2473
1307 static_always_inline void
1308 encaps_processing_v4 (vlib_node_runtime_t * node,
1310 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1313 ip6_sr_header_t *sr0;
1317 /* Inner IPv4: Decrement TTL & update checksum */
1318 ip0_encap->ttl -= 1;
1319 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1320 checksum0 += checksum0 >= 0xffff;
1321 ip0_encap->checksum = checksum0;
1323 /* Outer IPv6: Update length, FL, proto */
1324 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1325 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1326 ip0->ip_version_traffic_class_and_flow_label =
1327 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1328 ((ip0_encap->tos & 0xFF) << 20));
1329 sr0 = (void *) (ip0 + 1);
1330 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1334 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1337 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1338 vlib_frame_t * from_frame)
1340 ip6_sr_main_t *sm = &sr_main;
1341 u32 n_left_from, next_index, *from, *to_next;
1343 from = vlib_frame_vector_args (from_frame);
1344 n_left_from = from_frame->n_vectors;
1346 next_index = node->cached_next_index;
1348 int encap_pkts = 0, bsid_pkts = 0;
1350 while (n_left_from > 0)
1354 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1357 while (n_left_from >= 8 && n_left_to_next >= 4)
1359 u32 bi0, bi1, bi2, bi3;
1360 vlib_buffer_t *b0, *b1, *b2, *b3;
1361 u32 next0, next1, next2, next3;
1362 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1363 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1364 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1365 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1367 /* Prefetch next iteration. */
1369 vlib_buffer_t *p4, *p5, *p6, *p7;
1371 p4 = vlib_get_buffer (vm, from[4]);
1372 p5 = vlib_get_buffer (vm, from[5]);
1373 p6 = vlib_get_buffer (vm, from[6]);
1374 p7 = vlib_get_buffer (vm, from[7]);
1376 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1377 vlib_prefetch_buffer_header (p4, LOAD);
1378 vlib_prefetch_buffer_header (p5, LOAD);
1379 vlib_prefetch_buffer_header (p6, LOAD);
1380 vlib_prefetch_buffer_header (p7, LOAD);
1382 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1383 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1384 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1385 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1388 to_next[0] = bi0 = from[0];
1389 to_next[1] = bi1 = from[1];
1390 to_next[2] = bi2 = from[2];
1391 to_next[3] = bi3 = from[3];
1395 n_left_to_next -= 4;
1397 b0 = vlib_get_buffer (vm, bi0);
1398 b1 = vlib_get_buffer (vm, bi1);
1399 b2 = vlib_get_buffer (vm, bi2);
1400 b3 = vlib_get_buffer (vm, bi3);
1403 pool_elt_at_index (sm->sid_lists,
1404 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1406 pool_elt_at_index (sm->sid_lists,
1407 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1409 pool_elt_at_index (sm->sid_lists,
1410 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1412 pool_elt_at_index (sm->sid_lists,
1413 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1414 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1415 vec_len (sl0->rewrite));
1416 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1417 vec_len (sl1->rewrite));
1418 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1419 vec_len (sl2->rewrite));
1420 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1421 vec_len (sl3->rewrite));
1423 ip0_encap = vlib_buffer_get_current (b0);
1424 ip1_encap = vlib_buffer_get_current (b1);
1425 ip2_encap = vlib_buffer_get_current (b2);
1426 ip3_encap = vlib_buffer_get_current (b3);
1428 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1429 sl0->rewrite, vec_len (sl0->rewrite));
1430 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1431 sl1->rewrite, vec_len (sl1->rewrite));
1432 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1433 sl2->rewrite, vec_len (sl2->rewrite));
1434 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1435 sl3->rewrite, vec_len (sl3->rewrite));
1437 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1438 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1439 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1440 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1442 ip0 = vlib_buffer_get_current (b0);
1443 ip1 = vlib_buffer_get_current (b1);
1444 ip2 = vlib_buffer_get_current (b2);
1445 ip3 = vlib_buffer_get_current (b3);
1447 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1448 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1449 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1450 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1452 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1454 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1456 sr_policy_rewrite_trace_t *tr =
1457 vlib_add_trace (vm, node, b0, sizeof (*tr));
1458 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1459 sizeof (tr->src.as_u8));
1460 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1461 sizeof (tr->dst.as_u8));
1464 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1466 sr_policy_rewrite_trace_t *tr =
1467 vlib_add_trace (vm, node, b1, sizeof (*tr));
1468 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1469 sizeof (tr->src.as_u8));
1470 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1471 sizeof (tr->dst.as_u8));
1474 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1476 sr_policy_rewrite_trace_t *tr =
1477 vlib_add_trace (vm, node, b2, sizeof (*tr));
1478 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1479 sizeof (tr->src.as_u8));
1480 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1481 sizeof (tr->dst.as_u8));
1484 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1486 sr_policy_rewrite_trace_t *tr =
1487 vlib_add_trace (vm, node, b3, sizeof (*tr));
1488 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1489 sizeof (tr->src.as_u8));
1490 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1491 sizeof (tr->dst.as_u8));
1496 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1497 n_left_to_next, bi0, bi1, bi2, bi3,
1498 next0, next1, next2, next3);
1501 /* Single loop for potentially the last three packets */
1502 while (n_left_from > 0 && n_left_to_next > 0)
1506 ip6_header_t *ip0 = 0;
1507 ip4_header_t *ip0_encap = 0;
1509 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1516 n_left_to_next -= 1;
1517 b0 = vlib_get_buffer (vm, bi0);
1520 pool_elt_at_index (sm->sid_lists,
1521 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1522 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1523 vec_len (sl0->rewrite));
1525 ip0_encap = vlib_buffer_get_current (b0);
1527 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1528 sl0->rewrite, vec_len (sl0->rewrite));
1529 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1531 ip0 = vlib_buffer_get_current (b0);
1533 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1535 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1536 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1538 sr_policy_rewrite_trace_t *tr =
1539 vlib_add_trace (vm, node, b0, sizeof (*tr));
1540 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1541 sizeof (tr->src.as_u8));
1542 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1543 sizeof (tr->dst.as_u8));
1547 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1548 n_left_to_next, bi0, next0);
1551 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1554 /* Update counters */
1555 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1556 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1558 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1559 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1562 return from_frame->n_vectors;
1566 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1567 .function = sr_policy_rewrite_encaps_v4,
1568 .name = "sr-pl-rewrite-encaps-v4",
1569 .vector_size = sizeof (u32),
1570 .format_trace = format_sr_policy_rewrite_trace,
1571 .type = VLIB_NODE_TYPE_INTERNAL,
1572 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1573 .error_strings = sr_policy_rewrite_error_strings,
1574 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1576 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1577 foreach_sr_policy_rewrite_next
1584 ip_flow_hash (void *data)
1586 ip4_header_t *iph = (ip4_header_t *) data;
1588 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1589 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1591 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1597 return (*((u64 *) m) & 0xffffffffffff);
1601 l2_flow_hash (vlib_buffer_t * b0)
1603 ethernet_header_t *eh;
1605 uword is_ip, eh_size;
1608 eh = vlib_buffer_get_current (b0);
1609 eh_type = clib_net_to_host_u16 (eh->type);
1610 eh_size = ethernet_buffer_header_size (b0);
1612 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1614 /* since we have 2 cache lines, use them */
1616 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1620 b = mac_to_u64 ((u8 *) eh->dst_address);
1621 c = mac_to_u64 ((u8 *) eh->src_address);
1622 hash_mix64 (a, b, c);
1628 * @brief Graph node for applying a SR policy into a L2 frame
1631 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1632 vlib_frame_t * from_frame)
1634 ip6_sr_main_t *sm = &sr_main;
1635 u32 n_left_from, next_index, *from, *to_next;
1637 from = vlib_frame_vector_args (from_frame);
1638 n_left_from = from_frame->n_vectors;
1640 next_index = node->cached_next_index;
1642 int encap_pkts = 0, bsid_pkts = 0;
1644 while (n_left_from > 0)
1648 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1651 while (n_left_from >= 8 && n_left_to_next >= 4)
1653 u32 bi0, bi1, bi2, bi3;
1654 vlib_buffer_t *b0, *b1, *b2, *b3;
1655 u32 next0, next1, next2, next3;
1656 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1657 ethernet_header_t *en0, *en1, *en2, *en3;
1658 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1659 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1660 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1661 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1663 /* Prefetch next iteration. */
1665 vlib_buffer_t *p4, *p5, *p6, *p7;
1667 p4 = vlib_get_buffer (vm, from[4]);
1668 p5 = vlib_get_buffer (vm, from[5]);
1669 p6 = vlib_get_buffer (vm, from[6]);
1670 p7 = vlib_get_buffer (vm, from[7]);
1672 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1673 vlib_prefetch_buffer_header (p4, LOAD);
1674 vlib_prefetch_buffer_header (p5, LOAD);
1675 vlib_prefetch_buffer_header (p6, LOAD);
1676 vlib_prefetch_buffer_header (p7, LOAD);
1678 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1679 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1680 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1681 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1684 to_next[0] = bi0 = from[0];
1685 to_next[1] = bi1 = from[1];
1686 to_next[2] = bi2 = from[2];
1687 to_next[3] = bi3 = from[3];
1691 n_left_to_next -= 4;
1693 b0 = vlib_get_buffer (vm, bi0);
1694 b1 = vlib_get_buffer (vm, bi1);
1695 b2 = vlib_get_buffer (vm, bi2);
1696 b3 = vlib_get_buffer (vm, bi3);
1698 sp0 = pool_elt_at_index (sm->sr_policies,
1699 sm->sw_iface_sr_policies[vnet_buffer
1703 sp1 = pool_elt_at_index (sm->sr_policies,
1704 sm->sw_iface_sr_policies[vnet_buffer
1708 sp2 = pool_elt_at_index (sm->sr_policies,
1709 sm->sw_iface_sr_policies[vnet_buffer
1713 sp3 = pool_elt_at_index (sm->sr_policies,
1714 sm->sw_iface_sr_policies[vnet_buffer
1718 if (vec_len (sp0->segments_lists) == 1)
1719 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1722 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1723 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1724 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1725 (vec_len (sp0->segments_lists) - 1))];
1728 if (vec_len (sp1->segments_lists) == 1)
1729 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1732 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1733 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1734 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1735 (vec_len (sp1->segments_lists) - 1))];
1738 if (vec_len (sp2->segments_lists) == 1)
1739 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1742 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1743 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1744 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1745 (vec_len (sp2->segments_lists) - 1))];
1748 if (vec_len (sp3->segments_lists) == 1)
1749 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1752 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1753 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1754 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1755 (vec_len (sp3->segments_lists) - 1))];
1759 pool_elt_at_index (sm->sid_lists,
1760 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1762 pool_elt_at_index (sm->sid_lists,
1763 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1765 pool_elt_at_index (sm->sid_lists,
1766 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1768 pool_elt_at_index (sm->sid_lists,
1769 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1771 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1772 vec_len (sl0->rewrite));
1773 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1774 vec_len (sl1->rewrite));
1775 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1776 vec_len (sl2->rewrite));
1777 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1778 vec_len (sl3->rewrite));
1780 en0 = vlib_buffer_get_current (b0);
1781 en1 = vlib_buffer_get_current (b1);
1782 en2 = vlib_buffer_get_current (b2);
1783 en3 = vlib_buffer_get_current (b3);
1785 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1786 vec_len (sl0->rewrite));
1787 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1788 vec_len (sl1->rewrite));
1789 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1790 vec_len (sl2->rewrite));
1791 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1792 vec_len (sl3->rewrite));
1794 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1795 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1796 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1797 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1799 ip0 = vlib_buffer_get_current (b0);
1800 ip1 = vlib_buffer_get_current (b1);
1801 ip2 = vlib_buffer_get_current (b2);
1802 ip3 = vlib_buffer_get_current (b3);
1804 ip0->payload_length =
1805 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1806 ip1->payload_length =
1807 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1808 ip2->payload_length =
1809 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1810 ip3->payload_length =
1811 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1813 sr0 = (void *) (ip0 + 1);
1814 sr1 = (void *) (ip1 + 1);
1815 sr2 = (void *) (ip2 + 1);
1816 sr3 = (void *) (ip3 + 1);
1818 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1819 IP_PROTOCOL_IP6_NONXT;
1821 /* Which Traffic class and flow label do I set ? */
1822 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1824 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1826 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1828 sr_policy_rewrite_trace_t *tr =
1829 vlib_add_trace (vm, node, b0, sizeof (*tr));
1830 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1831 sizeof (tr->src.as_u8));
1832 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1833 sizeof (tr->dst.as_u8));
1836 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1838 sr_policy_rewrite_trace_t *tr =
1839 vlib_add_trace (vm, node, b1, sizeof (*tr));
1840 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1841 sizeof (tr->src.as_u8));
1842 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1843 sizeof (tr->dst.as_u8));
1846 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1848 sr_policy_rewrite_trace_t *tr =
1849 vlib_add_trace (vm, node, b2, sizeof (*tr));
1850 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1851 sizeof (tr->src.as_u8));
1852 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1853 sizeof (tr->dst.as_u8));
1856 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1858 sr_policy_rewrite_trace_t *tr =
1859 vlib_add_trace (vm, node, b3, sizeof (*tr));
1860 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1861 sizeof (tr->src.as_u8));
1862 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1863 sizeof (tr->dst.as_u8));
1868 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1869 n_left_to_next, bi0, bi1, bi2, bi3,
1870 next0, next1, next2, next3);
1873 /* Single loop for potentially the last three packets */
1874 while (n_left_from > 0 && n_left_to_next > 0)
1878 ip6_header_t *ip0 = 0;
1879 ip6_sr_header_t *sr0;
1880 ethernet_header_t *en0;
1881 ip6_sr_policy_t *sp0;
1883 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1890 n_left_to_next -= 1;
1891 b0 = vlib_get_buffer (vm, bi0);
1893 /* Find the SR policy */
1894 sp0 = pool_elt_at_index (sm->sr_policies,
1895 sm->sw_iface_sr_policies[vnet_buffer
1899 /* In case there is more than one SL, LB among them */
1900 if (vec_len (sp0->segments_lists) == 1)
1901 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1904 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1905 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1906 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1907 (vec_len (sp0->segments_lists) - 1))];
1910 pool_elt_at_index (sm->sid_lists,
1911 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1912 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1913 vec_len (sl0->rewrite));
1915 en0 = vlib_buffer_get_current (b0);
1917 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1918 vec_len (sl0->rewrite));
1920 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1922 ip0 = vlib_buffer_get_current (b0);
1924 ip0->payload_length =
1925 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1927 sr0 = (void *) (ip0 + 1);
1928 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1930 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1931 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1933 sr_policy_rewrite_trace_t *tr =
1934 vlib_add_trace (vm, node, b0, sizeof (*tr));
1935 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1936 sizeof (tr->src.as_u8));
1937 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1938 sizeof (tr->dst.as_u8));
1942 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1943 n_left_to_next, bi0, next0);
1946 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1949 /* Update counters */
1950 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1951 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1953 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1954 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1957 return from_frame->n_vectors;
1961 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1962 .function = sr_policy_rewrite_encaps_l2,
1963 .name = "sr-pl-rewrite-encaps-l2",
1964 .vector_size = sizeof (u32),
1965 .format_trace = format_sr_policy_rewrite_trace,
1966 .type = VLIB_NODE_TYPE_INTERNAL,
1967 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1968 .error_strings = sr_policy_rewrite_error_strings,
1969 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1971 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1972 foreach_sr_policy_rewrite_next
1979 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1982 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1983 vlib_frame_t * from_frame)
1985 ip6_sr_main_t *sm = &sr_main;
1986 u32 n_left_from, next_index, *from, *to_next;
1988 from = vlib_frame_vector_args (from_frame);
1989 n_left_from = from_frame->n_vectors;
1991 next_index = node->cached_next_index;
1993 int insert_pkts = 0, bsid_pkts = 0;
1995 while (n_left_from > 0)
1999 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2002 while (n_left_from >= 8 && n_left_to_next >= 4)
2004 u32 bi0, bi1, bi2, bi3;
2005 vlib_buffer_t *b0, *b1, *b2, *b3;
2006 u32 next0, next1, next2, next3;
2007 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2008 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2009 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2010 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2011 u16 new_l0, new_l1, new_l2, new_l3;
2013 /* Prefetch next iteration. */
2015 vlib_buffer_t *p4, *p5, *p6, *p7;
2017 p4 = vlib_get_buffer (vm, from[4]);
2018 p5 = vlib_get_buffer (vm, from[5]);
2019 p6 = vlib_get_buffer (vm, from[6]);
2020 p7 = vlib_get_buffer (vm, from[7]);
2022 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2023 vlib_prefetch_buffer_header (p4, LOAD);
2024 vlib_prefetch_buffer_header (p5, LOAD);
2025 vlib_prefetch_buffer_header (p6, LOAD);
2026 vlib_prefetch_buffer_header (p7, LOAD);
2028 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2029 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2030 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2031 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2034 to_next[0] = bi0 = from[0];
2035 to_next[1] = bi1 = from[1];
2036 to_next[2] = bi2 = from[2];
2037 to_next[3] = bi3 = from[3];
2041 n_left_to_next -= 4;
2043 b0 = vlib_get_buffer (vm, bi0);
2044 b1 = vlib_get_buffer (vm, bi1);
2045 b2 = vlib_get_buffer (vm, bi2);
2046 b3 = vlib_get_buffer (vm, bi3);
2049 pool_elt_at_index (sm->sid_lists,
2050 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2052 pool_elt_at_index (sm->sid_lists,
2053 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2055 pool_elt_at_index (sm->sid_lists,
2056 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2058 pool_elt_at_index (sm->sid_lists,
2059 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2060 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2061 vec_len (sl0->rewrite));
2062 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2063 vec_len (sl1->rewrite));
2064 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2065 vec_len (sl2->rewrite));
2066 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2067 vec_len (sl3->rewrite));
2069 ip0 = vlib_buffer_get_current (b0);
2070 ip1 = vlib_buffer_get_current (b1);
2071 ip2 = vlib_buffer_get_current (b2);
2072 ip3 = vlib_buffer_get_current (b3);
2074 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2076 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2077 ip6_ext_header_len (ip0 + 1));
2079 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2081 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2083 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2084 ip6_ext_header_len (ip1 + 1));
2086 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2088 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2090 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2091 ip6_ext_header_len (ip2 + 1));
2093 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2095 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2097 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2098 ip6_ext_header_len (ip3 + 1));
2100 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2102 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2103 (void *) sr0 - (void *) ip0);
2104 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2105 (void *) sr1 - (void *) ip1);
2106 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2107 (void *) sr2 - (void *) ip2);
2108 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2109 (void *) sr3 - (void *) ip3);
2111 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2112 vec_len (sl0->rewrite));
2113 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2114 vec_len (sl1->rewrite));
2115 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2116 vec_len (sl2->rewrite));
2117 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2118 vec_len (sl3->rewrite));
2120 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2121 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2122 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2123 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2125 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2126 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2127 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2128 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2130 ip0->hop_limit -= 1;
2131 ip1->hop_limit -= 1;
2132 ip2->hop_limit -= 1;
2133 ip3->hop_limit -= 1;
2136 clib_net_to_host_u16 (ip0->payload_length) +
2137 vec_len (sl0->rewrite);
2139 clib_net_to_host_u16 (ip1->payload_length) +
2140 vec_len (sl1->rewrite);
2142 clib_net_to_host_u16 (ip2->payload_length) +
2143 vec_len (sl2->rewrite);
2145 clib_net_to_host_u16 (ip3->payload_length) +
2146 vec_len (sl3->rewrite);
2148 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2149 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2150 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2151 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2153 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2154 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2155 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2156 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2158 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2159 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2160 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2161 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2162 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2163 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2164 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2165 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2167 ip0->dst_address.as_u64[0] =
2168 (sr0->segments + sr0->segments_left)->as_u64[0];
2169 ip0->dst_address.as_u64[1] =
2170 (sr0->segments + sr0->segments_left)->as_u64[1];
2171 ip1->dst_address.as_u64[0] =
2172 (sr1->segments + sr1->segments_left)->as_u64[0];
2173 ip1->dst_address.as_u64[1] =
2174 (sr1->segments + sr1->segments_left)->as_u64[1];
2175 ip2->dst_address.as_u64[0] =
2176 (sr2->segments + sr2->segments_left)->as_u64[0];
2177 ip2->dst_address.as_u64[1] =
2178 (sr2->segments + sr2->segments_left)->as_u64[1];
2179 ip3->dst_address.as_u64[0] =
2180 (sr3->segments + sr3->segments_left)->as_u64[0];
2181 ip3->dst_address.as_u64[1] =
2182 (sr3->segments + sr3->segments_left)->as_u64[1];
2184 ip6_ext_header_t *ip_ext;
2185 if (ip0 + 1 == (void *) sr0)
2187 sr0->protocol = ip0->protocol;
2188 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2192 ip_ext = (void *) (ip0 + 1);
2193 sr0->protocol = ip_ext->next_hdr;
2194 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2197 if (ip1 + 1 == (void *) sr1)
2199 sr1->protocol = ip1->protocol;
2200 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2204 ip_ext = (void *) (ip2 + 1);
2205 sr2->protocol = ip_ext->next_hdr;
2206 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2209 if (ip2 + 1 == (void *) sr2)
2211 sr2->protocol = ip2->protocol;
2212 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2216 ip_ext = (void *) (ip2 + 1);
2217 sr2->protocol = ip_ext->next_hdr;
2218 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2221 if (ip3 + 1 == (void *) sr3)
2223 sr3->protocol = ip3->protocol;
2224 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2228 ip_ext = (void *) (ip3 + 1);
2229 sr3->protocol = ip_ext->next_hdr;
2230 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2235 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2237 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2239 sr_policy_rewrite_trace_t *tr =
2240 vlib_add_trace (vm, node, b0, sizeof (*tr));
2241 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2242 sizeof (tr->src.as_u8));
2243 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2244 sizeof (tr->dst.as_u8));
2247 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2249 sr_policy_rewrite_trace_t *tr =
2250 vlib_add_trace (vm, node, b1, sizeof (*tr));
2251 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2252 sizeof (tr->src.as_u8));
2253 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2254 sizeof (tr->dst.as_u8));
2257 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2259 sr_policy_rewrite_trace_t *tr =
2260 vlib_add_trace (vm, node, b2, sizeof (*tr));
2261 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2262 sizeof (tr->src.as_u8));
2263 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2264 sizeof (tr->dst.as_u8));
2267 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2269 sr_policy_rewrite_trace_t *tr =
2270 vlib_add_trace (vm, node, b3, sizeof (*tr));
2271 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2272 sizeof (tr->src.as_u8));
2273 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2274 sizeof (tr->dst.as_u8));
2278 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2279 n_left_to_next, bi0, bi1, bi2, bi3,
2280 next0, next1, next2, next3);
2283 /* Single loop for potentially the last three packets */
2284 while (n_left_from > 0 && n_left_to_next > 0)
2288 ip6_header_t *ip0 = 0;
2289 ip6_sr_header_t *sr0 = 0;
2291 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2299 n_left_to_next -= 1;
2301 b0 = vlib_get_buffer (vm, bi0);
2303 pool_elt_at_index (sm->sid_lists,
2304 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2305 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2306 vec_len (sl0->rewrite));
2308 ip0 = vlib_buffer_get_current (b0);
2310 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2312 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2313 ip6_ext_header_len (ip0 + 1));
2315 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2317 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2318 (void *) sr0 - (void *) ip0);
2319 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2320 vec_len (sl0->rewrite));
2322 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2324 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2325 ip0->hop_limit -= 1;
2327 clib_net_to_host_u16 (ip0->payload_length) +
2328 vec_len (sl0->rewrite);
2329 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2331 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2332 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2333 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2335 ip0->dst_address.as_u64[0] =
2336 (sr0->segments + sr0->segments_left)->as_u64[0];
2337 ip0->dst_address.as_u64[1] =
2338 (sr0->segments + sr0->segments_left)->as_u64[1];
2340 if (ip0 + 1 == (void *) sr0)
2342 sr0->protocol = ip0->protocol;
2343 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2347 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2348 sr0->protocol = ip_ext->next_hdr;
2349 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2352 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2353 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2355 sr_policy_rewrite_trace_t *tr =
2356 vlib_add_trace (vm, node, b0, sizeof (*tr));
2357 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2358 sizeof (tr->src.as_u8));
2359 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2360 sizeof (tr->dst.as_u8));
2365 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2366 n_left_to_next, bi0, next0);
2369 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2372 /* Update counters */
2373 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2374 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2376 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2377 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2379 return from_frame->n_vectors;
2383 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2384 .function = sr_policy_rewrite_insert,
2385 .name = "sr-pl-rewrite-insert",
2386 .vector_size = sizeof (u32),
2387 .format_trace = format_sr_policy_rewrite_trace,
2388 .type = VLIB_NODE_TYPE_INTERNAL,
2389 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2390 .error_strings = sr_policy_rewrite_error_strings,
2391 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2393 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2394 foreach_sr_policy_rewrite_next
2401 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2404 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2405 vlib_frame_t * from_frame)
2407 ip6_sr_main_t *sm = &sr_main;
2408 u32 n_left_from, next_index, *from, *to_next;
2410 from = vlib_frame_vector_args (from_frame);
2411 n_left_from = from_frame->n_vectors;
2413 next_index = node->cached_next_index;
2415 int insert_pkts = 0, bsid_pkts = 0;
2417 while (n_left_from > 0)
2421 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2424 while (n_left_from >= 8 && n_left_to_next >= 4)
2426 u32 bi0, bi1, bi2, bi3;
2427 vlib_buffer_t *b0, *b1, *b2, *b3;
2428 u32 next0, next1, next2, next3;
2429 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2430 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2431 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2432 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2433 u16 new_l0, new_l1, new_l2, new_l3;
2435 /* Prefetch next iteration. */
2437 vlib_buffer_t *p4, *p5, *p6, *p7;
2439 p4 = vlib_get_buffer (vm, from[4]);
2440 p5 = vlib_get_buffer (vm, from[5]);
2441 p6 = vlib_get_buffer (vm, from[6]);
2442 p7 = vlib_get_buffer (vm, from[7]);
2444 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2445 vlib_prefetch_buffer_header (p4, LOAD);
2446 vlib_prefetch_buffer_header (p5, LOAD);
2447 vlib_prefetch_buffer_header (p6, LOAD);
2448 vlib_prefetch_buffer_header (p7, LOAD);
2450 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2451 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2452 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2453 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2456 to_next[0] = bi0 = from[0];
2457 to_next[1] = bi1 = from[1];
2458 to_next[2] = bi2 = from[2];
2459 to_next[3] = bi3 = from[3];
2463 n_left_to_next -= 4;
2465 b0 = vlib_get_buffer (vm, bi0);
2466 b1 = vlib_get_buffer (vm, bi1);
2467 b2 = vlib_get_buffer (vm, bi2);
2468 b3 = vlib_get_buffer (vm, bi3);
2471 pool_elt_at_index (sm->sid_lists,
2472 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2474 pool_elt_at_index (sm->sid_lists,
2475 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2477 pool_elt_at_index (sm->sid_lists,
2478 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2480 pool_elt_at_index (sm->sid_lists,
2481 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2482 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2483 vec_len (sl0->rewrite_bsid));
2484 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2485 vec_len (sl1->rewrite_bsid));
2486 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2487 vec_len (sl2->rewrite_bsid));
2488 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2489 vec_len (sl3->rewrite_bsid));
2491 ip0 = vlib_buffer_get_current (b0);
2492 ip1 = vlib_buffer_get_current (b1);
2493 ip2 = vlib_buffer_get_current (b2);
2494 ip3 = vlib_buffer_get_current (b3);
2496 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2498 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2499 ip6_ext_header_len (ip0 + 1));
2501 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2503 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2505 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2506 ip6_ext_header_len (ip1 + 1));
2508 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2510 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2512 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2513 ip6_ext_header_len (ip2 + 1));
2515 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2517 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2519 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2520 ip6_ext_header_len (ip3 + 1));
2522 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2524 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2525 (void *) sr0 - (void *) ip0);
2526 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2527 (void *) sr1 - (void *) ip1);
2528 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2529 (void *) sr2 - (void *) ip2);
2530 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2531 (void *) sr3 - (void *) ip3);
2533 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2534 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2535 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2536 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2537 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2538 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2539 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2540 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2542 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2543 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2544 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2545 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2547 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2548 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2549 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2550 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2552 ip0->hop_limit -= 1;
2553 ip1->hop_limit -= 1;
2554 ip2->hop_limit -= 1;
2555 ip3->hop_limit -= 1;
2558 clib_net_to_host_u16 (ip0->payload_length) +
2559 vec_len (sl0->rewrite_bsid);
2561 clib_net_to_host_u16 (ip1->payload_length) +
2562 vec_len (sl1->rewrite_bsid);
2564 clib_net_to_host_u16 (ip2->payload_length) +
2565 vec_len (sl2->rewrite_bsid);
2567 clib_net_to_host_u16 (ip3->payload_length) +
2568 vec_len (sl3->rewrite_bsid);
2570 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2571 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2572 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2573 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2575 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2576 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2577 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2578 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2580 ip0->dst_address.as_u64[0] =
2581 (sr0->segments + sr0->segments_left)->as_u64[0];
2582 ip0->dst_address.as_u64[1] =
2583 (sr0->segments + sr0->segments_left)->as_u64[1];
2584 ip1->dst_address.as_u64[0] =
2585 (sr1->segments + sr1->segments_left)->as_u64[0];
2586 ip1->dst_address.as_u64[1] =
2587 (sr1->segments + sr1->segments_left)->as_u64[1];
2588 ip2->dst_address.as_u64[0] =
2589 (sr2->segments + sr2->segments_left)->as_u64[0];
2590 ip2->dst_address.as_u64[1] =
2591 (sr2->segments + sr2->segments_left)->as_u64[1];
2592 ip3->dst_address.as_u64[0] =
2593 (sr3->segments + sr3->segments_left)->as_u64[0];
2594 ip3->dst_address.as_u64[1] =
2595 (sr3->segments + sr3->segments_left)->as_u64[1];
2597 ip6_ext_header_t *ip_ext;
2598 if (ip0 + 1 == (void *) sr0)
2600 sr0->protocol = ip0->protocol;
2601 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2605 ip_ext = (void *) (ip0 + 1);
2606 sr0->protocol = ip_ext->next_hdr;
2607 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2610 if (ip1 + 1 == (void *) sr1)
2612 sr1->protocol = ip1->protocol;
2613 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2617 ip_ext = (void *) (ip2 + 1);
2618 sr2->protocol = ip_ext->next_hdr;
2619 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2622 if (ip2 + 1 == (void *) sr2)
2624 sr2->protocol = ip2->protocol;
2625 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2629 ip_ext = (void *) (ip2 + 1);
2630 sr2->protocol = ip_ext->next_hdr;
2631 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2634 if (ip3 + 1 == (void *) sr3)
2636 sr3->protocol = ip3->protocol;
2637 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2641 ip_ext = (void *) (ip3 + 1);
2642 sr3->protocol = ip_ext->next_hdr;
2643 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2648 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2650 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2652 sr_policy_rewrite_trace_t *tr =
2653 vlib_add_trace (vm, node, b0, sizeof (*tr));
2654 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2655 sizeof (tr->src.as_u8));
2656 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2657 sizeof (tr->dst.as_u8));
2660 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2662 sr_policy_rewrite_trace_t *tr =
2663 vlib_add_trace (vm, node, b1, sizeof (*tr));
2664 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2665 sizeof (tr->src.as_u8));
2666 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2667 sizeof (tr->dst.as_u8));
2670 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2672 sr_policy_rewrite_trace_t *tr =
2673 vlib_add_trace (vm, node, b2, sizeof (*tr));
2674 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2675 sizeof (tr->src.as_u8));
2676 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2677 sizeof (tr->dst.as_u8));
2680 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2682 sr_policy_rewrite_trace_t *tr =
2683 vlib_add_trace (vm, node, b3, sizeof (*tr));
2684 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2685 sizeof (tr->src.as_u8));
2686 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2687 sizeof (tr->dst.as_u8));
2691 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2692 n_left_to_next, bi0, bi1, bi2, bi3,
2693 next0, next1, next2, next3);
2696 /* Single loop for potentially the last three packets */
2697 while (n_left_from > 0 && n_left_to_next > 0)
2701 ip6_header_t *ip0 = 0;
2702 ip6_sr_header_t *sr0 = 0;
2704 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2712 n_left_to_next -= 1;
2714 b0 = vlib_get_buffer (vm, bi0);
2716 pool_elt_at_index (sm->sid_lists,
2717 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2718 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2719 vec_len (sl0->rewrite_bsid));
2721 ip0 = vlib_buffer_get_current (b0);
2723 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2725 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2726 ip6_ext_header_len (ip0 + 1));
2728 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2730 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2731 (void *) sr0 - (void *) ip0);
2732 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2733 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2735 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2737 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2738 ip0->hop_limit -= 1;
2740 clib_net_to_host_u16 (ip0->payload_length) +
2741 vec_len (sl0->rewrite_bsid);
2742 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2744 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2746 ip0->dst_address.as_u64[0] =
2747 (sr0->segments + sr0->segments_left)->as_u64[0];
2748 ip0->dst_address.as_u64[1] =
2749 (sr0->segments + sr0->segments_left)->as_u64[1];
2751 if (ip0 + 1 == (void *) sr0)
2753 sr0->protocol = ip0->protocol;
2754 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2758 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2759 sr0->protocol = ip_ext->next_hdr;
2760 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2763 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2764 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2766 sr_policy_rewrite_trace_t *tr =
2767 vlib_add_trace (vm, node, b0, sizeof (*tr));
2768 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2769 sizeof (tr->src.as_u8));
2770 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2771 sizeof (tr->dst.as_u8));
2776 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2777 n_left_to_next, bi0, next0);
2780 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2783 /* Update counters */
2784 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2785 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2787 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2788 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2790 return from_frame->n_vectors;
2794 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2795 .function = sr_policy_rewrite_b_insert,
2796 .name = "sr-pl-rewrite-b-insert",
2797 .vector_size = sizeof (u32),
2798 .format_trace = format_sr_policy_rewrite_trace,
2799 .type = VLIB_NODE_TYPE_INTERNAL,
2800 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2801 .error_strings = sr_policy_rewrite_error_strings,
2802 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2804 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2805 foreach_sr_policy_rewrite_next
2812 * @brief Function BSID encapsulation
2814 static_always_inline void
2815 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2818 ip6_sr_header_t * sr0, u32 * next0)
2820 ip6_address_t *new_dst0;
2822 if (PREDICT_FALSE (!sr0))
2823 goto error_bsid_encaps;
2825 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2827 if (PREDICT_TRUE (sr0->segments_left != 0))
2829 sr0->segments_left -= 1;
2830 new_dst0 = (ip6_address_t *) (sr0->segments);
2831 new_dst0 += sr0->segments_left;
2832 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2833 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2839 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2840 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2844 * @brief Graph node for applying a SR policy BSID - Encapsulation
2847 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2848 vlib_frame_t * from_frame)
2850 ip6_sr_main_t *sm = &sr_main;
2851 u32 n_left_from, next_index, *from, *to_next;
2853 from = vlib_frame_vector_args (from_frame);
2854 n_left_from = from_frame->n_vectors;
2856 next_index = node->cached_next_index;
2858 int encap_pkts = 0, bsid_pkts = 0;
2860 while (n_left_from > 0)
2864 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2867 while (n_left_from >= 8 && n_left_to_next >= 4)
2869 u32 bi0, bi1, bi2, bi3;
2870 vlib_buffer_t *b0, *b1, *b2, *b3;
2871 u32 next0, next1, next2, next3;
2872 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2873 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2874 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2875 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2876 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2877 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2879 /* Prefetch next iteration. */
2881 vlib_buffer_t *p4, *p5, *p6, *p7;
2883 p4 = vlib_get_buffer (vm, from[4]);
2884 p5 = vlib_get_buffer (vm, from[5]);
2885 p6 = vlib_get_buffer (vm, from[6]);
2886 p7 = vlib_get_buffer (vm, from[7]);
2888 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2889 vlib_prefetch_buffer_header (p4, LOAD);
2890 vlib_prefetch_buffer_header (p5, LOAD);
2891 vlib_prefetch_buffer_header (p6, LOAD);
2892 vlib_prefetch_buffer_header (p7, LOAD);
2894 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2895 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2896 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2897 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2900 to_next[0] = bi0 = from[0];
2901 to_next[1] = bi1 = from[1];
2902 to_next[2] = bi2 = from[2];
2903 to_next[3] = bi3 = from[3];
2907 n_left_to_next -= 4;
2909 b0 = vlib_get_buffer (vm, bi0);
2910 b1 = vlib_get_buffer (vm, bi1);
2911 b2 = vlib_get_buffer (vm, bi2);
2912 b3 = vlib_get_buffer (vm, bi3);
2915 pool_elt_at_index (sm->sid_lists,
2916 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2918 pool_elt_at_index (sm->sid_lists,
2919 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2921 pool_elt_at_index (sm->sid_lists,
2922 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2924 pool_elt_at_index (sm->sid_lists,
2925 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2926 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2927 vec_len (sl0->rewrite));
2928 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929 vec_len (sl1->rewrite));
2930 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2931 vec_len (sl2->rewrite));
2932 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2933 vec_len (sl3->rewrite));
2935 ip0_encap = vlib_buffer_get_current (b0);
2936 ip1_encap = vlib_buffer_get_current (b1);
2937 ip2_encap = vlib_buffer_get_current (b2);
2938 ip3_encap = vlib_buffer_get_current (b3);
2940 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2941 IP_PROTOCOL_IPV6_ROUTE);
2942 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2943 IP_PROTOCOL_IPV6_ROUTE);
2944 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2945 IP_PROTOCOL_IPV6_ROUTE);
2946 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2947 IP_PROTOCOL_IPV6_ROUTE);
2949 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2950 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2951 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2952 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2954 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2955 sl0->rewrite, vec_len (sl0->rewrite));
2956 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2957 sl1->rewrite, vec_len (sl1->rewrite));
2958 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2959 sl2->rewrite, vec_len (sl2->rewrite));
2960 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2961 sl3->rewrite, vec_len (sl3->rewrite));
2963 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2964 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2965 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2966 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2968 ip0 = vlib_buffer_get_current (b0);
2969 ip1 = vlib_buffer_get_current (b1);
2970 ip2 = vlib_buffer_get_current (b2);
2971 ip3 = vlib_buffer_get_current (b3);
2973 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2974 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2975 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2976 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2978 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2980 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2982 sr_policy_rewrite_trace_t *tr =
2983 vlib_add_trace (vm, node, b0, sizeof (*tr));
2984 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2985 sizeof (tr->src.as_u8));
2986 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2987 sizeof (tr->dst.as_u8));
2990 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2992 sr_policy_rewrite_trace_t *tr =
2993 vlib_add_trace (vm, node, b1, sizeof (*tr));
2994 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2995 sizeof (tr->src.as_u8));
2996 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2997 sizeof (tr->dst.as_u8));
3000 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3002 sr_policy_rewrite_trace_t *tr =
3003 vlib_add_trace (vm, node, b2, sizeof (*tr));
3004 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3005 sizeof (tr->src.as_u8));
3006 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3007 sizeof (tr->dst.as_u8));
3010 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3012 sr_policy_rewrite_trace_t *tr =
3013 vlib_add_trace (vm, node, b3, sizeof (*tr));
3014 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3015 sizeof (tr->src.as_u8));
3016 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3017 sizeof (tr->dst.as_u8));
3022 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3023 n_left_to_next, bi0, bi1, bi2, bi3,
3024 next0, next1, next2, next3);
3027 /* Single loop for potentially the last three packets */
3028 while (n_left_from > 0 && n_left_to_next > 0)
3032 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3033 ip6_ext_header_t *prev0;
3034 ip6_sr_header_t *sr0;
3036 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3043 n_left_to_next -= 1;
3044 b0 = vlib_get_buffer (vm, bi0);
3047 pool_elt_at_index (sm->sid_lists,
3048 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3049 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3050 vec_len (sl0->rewrite));
3052 ip0_encap = vlib_buffer_get_current (b0);
3053 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3054 IP_PROTOCOL_IPV6_ROUTE);
3055 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3057 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3058 sl0->rewrite, vec_len (sl0->rewrite));
3059 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3061 ip0 = vlib_buffer_get_current (b0);
3063 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3065 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3066 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3068 sr_policy_rewrite_trace_t *tr =
3069 vlib_add_trace (vm, node, b0, sizeof (*tr));
3070 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3071 sizeof (tr->src.as_u8));
3072 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3073 sizeof (tr->dst.as_u8));
3077 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3078 n_left_to_next, bi0, next0);
3081 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3084 /* Update counters */
3085 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3086 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3088 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3089 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3092 return from_frame->n_vectors;
3096 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3097 .function = sr_policy_rewrite_b_encaps,
3098 .name = "sr-pl-rewrite-b-encaps",
3099 .vector_size = sizeof (u32),
3100 .format_trace = format_sr_policy_rewrite_trace,
3101 .type = VLIB_NODE_TYPE_INTERNAL,
3102 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3103 .error_strings = sr_policy_rewrite_error_strings,
3104 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3106 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3107 foreach_sr_policy_rewrite_next
3113 /*************************** SR Segment Lists DPOs ****************************/
3115 format_sr_segment_list_dpo (u8 * s, va_list * args)
3117 ip6_sr_main_t *sm = &sr_main;
3118 ip6_address_t *addr;
3121 index_t index = va_arg (*args, index_t);
3122 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3123 s = format (s, "SR: Segment List index:[%d]", index);
3124 s = format (s, "\n\tSegments:");
3126 sl = pool_elt_at_index (sm->sid_lists, index);
3128 s = format (s, "< ");
3129 vec_foreach (addr, sl->segments)
3131 s = format (s, "%U, ", format_ip6_address, addr);
3133 s = format (s, "\b\b > - ");
3134 s = format (s, "Weight: %u", sl->weight);
3139 const static dpo_vft_t sr_policy_rewrite_vft = {
3140 .dv_lock = sr_dpo_lock,
3141 .dv_unlock = sr_dpo_unlock,
3142 .dv_format = format_sr_segment_list_dpo,
3145 const static char *const sr_pr_encaps_ip6_nodes[] = {
3146 "sr-pl-rewrite-encaps",
3150 const static char *const sr_pr_encaps_ip4_nodes[] = {
3151 "sr-pl-rewrite-encaps-v4",
3155 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3156 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3157 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3160 const static char *const sr_pr_insert_ip6_nodes[] = {
3161 "sr-pl-rewrite-insert",
3165 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3166 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3169 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3170 "sr-pl-rewrite-b-insert",
3174 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3175 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3178 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3179 "sr-pl-rewrite-b-encaps",
3183 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3184 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3187 /********************* SR Policy Rewrite initialization ***********************/
3189 * @brief SR Policy Rewrite initialization
3192 sr_policy_rewrite_init (vlib_main_t * vm)
3194 ip6_sr_main_t *sm = &sr_main;
3196 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3197 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3198 sizeof (ip6_address_t));
3200 /* Init SR VPO DPOs type */
3201 sr_pr_encaps_dpo_type =
3202 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3204 sr_pr_insert_dpo_type =
3205 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3207 sr_pr_bsid_encaps_dpo_type =
3208 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3210 sr_pr_bsid_insert_dpo_type =
3211 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3213 /* Register the L2 encaps node used in HW redirect */
3214 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3216 sm->fib_table_ip6 = (u32) ~ 0;
3217 sm->fib_table_ip4 = (u32) ~ 0;
3222 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3226 * fd.io coding-style-patch-verification: ON
3229 * eval: (c-set-style "gnu")