2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
115 static clib_error_t *
116 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
125 return clib_error_return (0, "No address specified");
127 return clib_error_return (0, "No address specified");
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132 .path = "set sr encaps source",
133 .short_help = "set sr encaps source addr <ip6_addr>",
134 .function = set_sr_src_command_fn,
138 /*********************** SR rewrite string computation ************************/
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
142 * @param sl is a vector of IPv6 addresses composing the Segment List
144 * @return precomputed rewrite string for encapsulation
147 compute_rewrite_encaps (ip6_address_t * sl)
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
163 vec_validate (rs, header_length - 1);
165 iph = (ip6_header_t *) rs;
166 iph->ip_version_traffic_class_and_flow_label =
167 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171 iph->protocol = IP_PROTOCOL_IPV6;
172 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
174 srh = (ip6_sr_header_t *) (iph + 1);
175 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176 srh->protocol = IP_PROTOCOL_IPV6;
177 srh->type = ROUTING_HEADER_TYPE_SR;
178 srh->segments_left = vec_len (sl) - 1;
179 srh->first_segment = vec_len (sl) - 1;
180 srh->length = ((sizeof (ip6_sr_header_t) +
181 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
196 * @brief SR rewrite string computation for SRH insertion (inline)
198 * @param sl is a vector of IPv6 addresses composing the Segment List
200 * @return precomputed rewrite string for SRH insertion
203 compute_rewrite_insert (ip6_address_t * sl)
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 srh = (ip6_sr_header_t *) rs;
217 srh->type = ROUTING_HEADER_TYPE_SR;
218 srh->segments_left = vec_len (sl);
219 srh->first_segment = vec_len (sl);
220 srh->length = ((sizeof (ip6_sr_header_t) +
221 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
236 * @param sl is a vector of IPv6 addresses composing the Segment List
238 * @return precomputed rewrite string for SRH insertion with BSID
241 compute_rewrite_bsid (ip6_address_t * sl)
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
252 vec_validate (rs, header_length - 1);
254 srh = (ip6_sr_header_t *) rs;
255 srh->type = ROUTING_HEADER_TYPE_SR;
256 srh->segments_left = vec_len (sl) - 1;
257 srh->first_segment = vec_len (sl) - 1;
258 srh->length = ((sizeof (ip6_sr_header_t) +
259 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
271 /*************************** SR LB helper functions **************************/
273 * @brief Creates a Segment List and adds it to an SR policy
275 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276 * not necessarily unique. Hence there might be two Segment List within the
277 * same SR Policy with exactly the same segments and same weight.
279 * @param sr_policy is the SR policy where the SL will be added
280 * @param sl is a vector of IPv6 addresses composing the Segment List
281 * @param weight is the weight of the SegmentList (for load-balancing purposes)
282 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
284 * @return pointer to the just created segment list
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
298 /* Fill in segment list */
299 segment_list->weight =
300 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301 segment_list->segments = vec_dup (sl);
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
321 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
322 segment_list - sm->sid_lists);
323 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
324 segment_list - sm->sid_lists);
325 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
326 DPO_PROTO_IP6, segment_list - sm->sid_lists);
330 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
331 segment_list - sm->sid_lists);
332 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
333 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 * @brief Updates the Load Balancer after an SR Policy change
342 * @param sr_policy is the modified SR Policy
345 update_lb (ip6_sr_policy_t * sr_policy)
347 flow_hash_config_t fhc;
349 ip6_sr_sl_t *segment_list;
350 ip6_sr_main_t *sm = &sr_main;
351 load_balance_path_t path;
352 path.path_index = FIB_NODE_INDEX_INVALID;
353 load_balance_path_t *ip4_path_vector = 0;
354 load_balance_path_t *ip6_path_vector = 0;
355 load_balance_path_t *b_path_vector = 0;
357 /* In case LB does not exist, create it */
358 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
361 .fp_proto = FIB_PROTOCOL_IP6,
364 .ip6 = sr_policy->bsid,
368 /* Add FIB entry for BSID */
369 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
370 dpo_proto_to_fib (DPO_PROTO_IP6));
372 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
373 load_balance_create (0, DPO_PROTO_IP6, fhc));
375 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
376 load_balance_create (0, DPO_PROTO_IP6, fhc));
378 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
379 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
380 sr_policy->fib_table),
382 FIB_ENTRY_FLAG_EXCLUSIVE,
383 &sr_policy->bsid_dpo);
385 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->ip6_dpo);
391 if (sr_policy->is_encap)
393 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
394 load_balance_create (0, DPO_PROTO_IP4, fhc));
396 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
399 FIB_ENTRY_FLAG_EXCLUSIVE,
400 &sr_policy->ip4_dpo);
405 /* Create the LB path vector */
406 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
407 vec_foreach (sl_index, sr_policy->segments_lists)
409 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
410 path.path_dpo = segment_list->bsid_dpo;
411 path.path_weight = segment_list->weight;
412 vec_add1 (b_path_vector, path);
413 path.path_dpo = segment_list->ip6_dpo;
414 vec_add1 (ip6_path_vector, path);
415 if (sr_policy->is_encap)
417 path.path_dpo = segment_list->ip4_dpo;
418 vec_add1 (ip4_path_vector, path);
422 /* Update LB multipath */
423 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
424 LOAD_BALANCE_FLAG_NONE);
425 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
426 LOAD_BALANCE_FLAG_NONE);
427 if (sr_policy->is_encap)
428 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
429 LOAD_BALANCE_FLAG_NONE);
432 vec_free (b_path_vector);
433 vec_free (ip6_path_vector);
434 vec_free (ip4_path_vector);
439 * @brief Updates the Replicate DPO after an SR Policy change
441 * @param sr_policy is the modified SR Policy (type spray)
444 update_replicate (ip6_sr_policy_t * sr_policy)
447 ip6_sr_sl_t *segment_list;
448 ip6_sr_main_t *sm = &sr_main;
449 load_balance_path_t path;
450 path.path_index = FIB_NODE_INDEX_INVALID;
451 load_balance_path_t *b_path_vector = 0;
452 load_balance_path_t *ip6_path_vector = 0;
453 load_balance_path_t *ip4_path_vector = 0;
455 /* In case LB does not exist, create it */
456 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
458 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
459 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
461 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
462 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
464 /* Update FIB entry's DPO to point to SR without LB */
466 .fp_proto = FIB_PROTOCOL_IP6,
469 .ip6 = sr_policy->bsid,
472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
484 if (sr_policy->is_encap)
486 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
487 replicate_create (0, DPO_PROTO_IP4));
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
498 /* Create the replicate path vector */
499 path.path_weight = 1;
500 vec_foreach (sl_index, sr_policy->segments_lists)
502 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
503 path.path_dpo = segment_list->bsid_dpo;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
514 /* Update replicate multipath */
515 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
516 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
517 if (sr_policy->is_encap)
518 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
521 /******************************* SR rewrite API *******************************/
522 /* Three functions for handling sr policies:
526 * All of them are API. CLI function on sr_policy_command_fn */
529 * @brief Create a new SR policy
531 * @param bsid is the bindingSID of the SR Policy
532 * @param segments is a vector of IPv6 address composing the segment list
533 * @param weight is the weight of the sid list. optional.
534 * @param behavior is the behavior of the SR policy. (default//spray)
535 * @param fib_table is the VRF where to install the FIB entry for the BSID
536 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
538 * @return 0 if correct, else error
541 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
542 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
544 ip6_sr_main_t *sm = &sr_main;
545 ip6_sr_policy_t *sr_policy = 0;
548 /* Search for existing keys (BSID) */
549 p = mhash_get (&sm->sr_policies_index_hash, bsid);
552 /* Add SR policy that already exists; complain */
556 /* Search collision in FIB entries */
557 /* Explanation: It might be possible that some other entity has already
558 * created a route for the BSID. This in theory is impossible, but in
559 * practise we could see it. Assert it and scream if needed */
561 .fp_proto = FIB_PROTOCOL_IP6,
568 /* Lookup the FIB index associated to the table selected */
569 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
570 (fib_table != (u32) ~ 0 ? fib_table : 0));
574 /* Lookup whether there exists an entry for the BSID */
575 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
576 if (FIB_NODE_INDEX_INVALID != fei)
577 return -12; //There is an entry for such lookup
579 /* Add an SR policy object */
580 pool_get (sm->sr_policies, sr_policy);
581 memset (sr_policy, 0, sizeof (*sr_policy));
582 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
583 sr_policy->type = behavior;
584 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
585 sr_policy->is_encap = is_encap;
588 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
591 /* Create a segment list and add the index to the SR policy */
592 create_sl (sr_policy, segments, weight, is_encap);
594 /* If FIB doesnt exist, create them */
595 if (sm->fib_table_ip6 == (u32) ~ 0)
597 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
598 "SRv6 steering of IP6 prefixes through BSIDs");
599 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
600 "SRv6 steering of IP4 prefixes through BSIDs");
603 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
604 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
605 update_lb (sr_policy);
606 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
607 update_replicate (sr_policy);
612 * @brief Delete a SR policy
614 * @param bsid is the bindingSID of the SR Policy
615 * @param index is the index of the SR policy
617 * @return 0 if correct, else error
620 sr_policy_del (ip6_address_t * bsid, u32 index)
622 ip6_sr_main_t *sm = &sr_main;
623 ip6_sr_policy_t *sr_policy = 0;
624 ip6_sr_sl_t *segment_list;
630 p = mhash_get (&sm->sr_policies_index_hash, bsid);
632 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
638 sr_policy = pool_elt_at_index (sm->sr_policies, index);
643 /* Remove BindingSID FIB entry */
645 .fp_proto = FIB_PROTOCOL_IP6,
648 .ip6 = sr_policy->bsid,
653 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
654 sr_policy->fib_table),
655 &pfx, FIB_SOURCE_SR);
657 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
659 if (sr_policy->is_encap)
660 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
662 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
664 dpo_reset (&sr_policy->bsid_dpo);
665 dpo_reset (&sr_policy->ip4_dpo);
666 dpo_reset (&sr_policy->ip6_dpo);
669 /* Clean SID Lists */
670 vec_foreach (sl_index, sr_policy->segments_lists)
672 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
673 vec_free (segment_list->segments);
674 vec_free (segment_list->rewrite);
675 vec_free (segment_list->rewrite_bsid);
676 pool_put_index (sm->sid_lists, *sl_index);
679 /* Remove SR policy entry */
680 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
681 pool_put (sm->sr_policies, sr_policy);
683 /* If FIB empty unlock it */
684 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
686 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6);
687 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6);
688 sm->fib_table_ip6 = (u32) ~ 0;
689 sm->fib_table_ip4 = (u32) ~ 0;
696 * @brief Modify an existing SR policy
698 * The possible modifications are adding a new Segment List, modifying an
699 * existing Segment List (modify the weight only) and delete a given
700 * Segment List from the SR Policy.
702 * @param bsid is the bindingSID of the SR Policy
703 * @param index is the index of the SR policy
704 * @param fib_table is the VRF where to install the FIB entry for the BSID
705 * @param operation is the operation to perform (among the top ones)
706 * @param segments is a vector of IPv6 address composing the segment list
707 * @param sl_index is the index of the Segment List to modify/delete
708 * @param weight is the weight of the sid list. optional.
709 * @param is_encap Mode. Encapsulation or SRH insertion.
711 * @return 0 if correct, else error
714 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
715 u8 operation, ip6_address_t * segments, u32 sl_index,
718 ip6_sr_main_t *sm = &sr_main;
719 ip6_sr_policy_t *sr_policy = 0;
720 ip6_sr_sl_t *segment_list;
721 u32 *sl_index_iterate;
726 p = mhash_get (&sm->sr_policies_index_hash, bsid);
728 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
734 sr_policy = pool_elt_at_index (sm->sr_policies, index);
739 if (operation == 1) /* Add SR List to an existing SR policy */
741 /* Create the new SL */
743 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
745 /* Create a new LB DPO */
746 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
747 update_lb (sr_policy);
748 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
749 update_replicate (sr_policy);
751 else if (operation == 2) /* Delete SR List from an existing SR policy */
753 /* Check that currently there are more than one SID list */
754 if (vec_len (sr_policy->segments_lists) == 1)
757 /* Check that the SR list does exist and is assigned to the sr policy */
758 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
759 if (*sl_index_iterate == sl_index)
762 if (*sl_index_iterate != sl_index)
765 /* Remove the lucky SR list that is being kicked out */
766 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
767 vec_free (segment_list->segments);
768 vec_free (segment_list->rewrite);
769 vec_free (segment_list->rewrite_bsid);
770 pool_put_index (sm->sid_lists, sl_index);
771 vec_del1 (sr_policy->segments_lists,
772 sl_index_iterate - sr_policy->segments_lists);
774 /* Create a new LB DPO */
775 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
776 update_lb (sr_policy);
777 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
778 update_replicate (sr_policy);
780 else if (operation == 3) /* Modify the weight of an existing SR List */
782 /* Find the corresponding SL */
783 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
784 if (*sl_index_iterate == sl_index)
787 if (*sl_index_iterate != sl_index)
790 /* Change the weight */
791 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
792 segment_list->weight = weight;
795 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
796 update_lb (sr_policy);
798 else /* Incorrect op. */
805 * @brief CLI for 'sr policies' command family
807 static clib_error_t *
808 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
809 vlib_cli_command_t * cmd)
812 char is_del = 0, is_add = 0, is_mod = 0;
814 ip6_address_t bsid, next_address;
815 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
816 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
817 ip6_address_t *segments = 0, *this_seg;
822 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
824 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
826 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
828 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
831 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
833 else if (!is_add && !policy_set
834 && unformat (input, "index %d", &sr_policy_index))
836 else if (unformat (input, "weight %d", &weight));
838 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
840 vec_add2 (segments, this_seg, 1);
841 clib_memcpy (this_seg->as_u8, next_address.as_u8,
844 else if (unformat (input, "add sl"))
846 else if (unformat (input, "del sl index %d", &sl_index))
848 else if (unformat (input, "mod sl index %d", &sl_index))
850 else if (fib_table == (u32) ~ 0
851 && unformat (input, "fib-table %d", &fib_table));
852 else if (unformat (input, "encap"))
854 else if (unformat (input, "insert"))
856 else if (unformat (input, "spray"))
862 if (!is_add && !is_mod && !is_del)
863 return clib_error_return (0, "Incorrect CLI");
866 return clib_error_return (0, "No SR policy BSID or index specified");
870 if (vec_len (segments) == 0)
871 return clib_error_return (0, "No Segment List specified");
872 rv = sr_policy_add (&bsid, segments, weight,
873 (is_spray ? SR_POLICY_TYPE_SPRAY :
874 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
877 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
882 return clib_error_return (0, "No SL modification specified");
883 if (operation != 1 && sl_index == (u32) ~ 0)
884 return clib_error_return (0, "No Segment List index specified");
885 if (operation == 1 && vec_len (segments) == 0)
886 return clib_error_return (0, "No Segment List specified");
887 if (operation == 3 && weight == (u32) ~ 0)
888 return clib_error_return (0, "No new weight for the SL specified");
889 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
890 sr_policy_index, fib_table, operation, segments,
901 return clib_error_return (0,
902 "There is already a FIB entry for the BindingSID address.\n"
903 "The SR policy could not be created.");
905 return clib_error_return (0, "The specified FIB table does not exist.");
907 return clib_error_return (0,
908 "The selected SR policy only contains ONE segment list. "
909 "Please remove the SR policy instead");
911 return clib_error_return (0,
912 "Could not delete the segment list. "
913 "It is not associated with that SR policy.");
915 return clib_error_return (0,
916 "Could not modify the segment list. "
917 "The given SL is not associated with such SR policy.");
919 return clib_error_return (0, "BUG: sr policy returns %d", rv);
925 VLIB_CLI_COMMAND (sr_policy_command, static) = {
927 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
928 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
930 "Manipulation of SR policies.\n"
931 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
932 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
933 "Segment Routing policies might be of type encapsulation or srh insertion\n"
934 "Each SR policy will be associated with a unique BindingSID.\n"
935 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
936 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
937 "The add command will create a SR policy with its first segment list (sl)\n"
938 "The mod command allows you to add, remove, or modify the existing segment lists\n"
939 "within an SR policy.\n"
940 "The del command allows you to delete a SR policy along with all its associated\n"
942 .function = sr_policy_command_fn,
947 * @brief CLI to display onscreen all the SR policies
949 static clib_error_t *
950 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
951 vlib_cli_command_t * cmd)
953 ip6_sr_main_t *sm = &sr_main;
955 ip6_sr_sl_t *segment_list = 0;
956 ip6_sr_policy_t *sr_policy = 0;
957 ip6_sr_policy_t **vec_policies = 0;
962 vlib_cli_output (vm, "SR policies:");
965 pool_foreach (sr_policy, sm->sr_policies,
966 {vec_add1 (vec_policies, sr_policy); } );
969 vec_foreach_index (i, vec_policies)
971 sr_policy = vec_policies[i];
972 vlib_cli_output (vm, "[%u].-\tBSID: %U",
973 (u32) (sr_policy - sm->sr_policies),
974 format_ip6_address, &sr_policy->bsid);
975 vlib_cli_output (vm, "\tBehavior: %s",
976 (sr_policy->is_encap ? "Encapsulation" :
978 vlib_cli_output (vm, "\tType: %s",
980 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
981 vlib_cli_output (vm, "\tFIB table: %u",
982 (sr_policy->fib_table !=
983 (u32) ~ 0 ? sr_policy->fib_table : 0));
984 vlib_cli_output (vm, "\tSegment Lists:");
985 vec_foreach (sl_index, sr_policy->segments_lists)
988 s = format (s, "\t[%u].- ", *sl_index);
989 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
990 s = format (s, "< ");
991 vec_foreach (addr, segment_list->segments)
993 s = format (s, "%U, ", format_ip6_address, addr);
995 s = format (s, "\b\b > ");
996 s = format (s, "weight: %u", segment_list->weight);
997 vlib_cli_output (vm, " %s", s);
999 vlib_cli_output (vm, "-----------");
1005 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1006 .path = "show sr policies",
1007 .short_help = "show sr policies",
1008 .function = show_sr_policies_command_fn,
1012 /*************************** SR rewrite graph node ****************************/
1014 * @brief Trace for the SR Policy Rewrite graph node
1017 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1020 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1021 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1022 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1025 (s, "SR-policy-rewrite: src %U dst %U",
1026 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1032 * @brief IPv6 encapsulation processing as per RFC2473
1034 static_always_inline void
1035 encaps_processing_v6 (vlib_node_runtime_t * node,
1037 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1041 ip0_encap->hop_limit -= 1;
1043 ip0->payload_length + sizeof (ip6_header_t) +
1044 clib_net_to_host_u16 (ip0_encap->payload_length);
1045 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1046 ip0->ip_version_traffic_class_and_flow_label =
1047 ip0_encap->ip_version_traffic_class_and_flow_label;
1051 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1054 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1055 vlib_frame_t * from_frame)
1057 ip6_sr_main_t *sm = &sr_main;
1058 u32 n_left_from, next_index, *from, *to_next;
1060 from = vlib_frame_vector_args (from_frame);
1061 n_left_from = from_frame->n_vectors;
1063 next_index = node->cached_next_index;
1065 int encap_pkts = 0, bsid_pkts = 0;
1067 while (n_left_from > 0)
1071 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1074 while (n_left_from >= 8 && n_left_to_next >= 4)
1076 u32 bi0, bi1, bi2, bi3;
1077 vlib_buffer_t *b0, *b1, *b2, *b3;
1078 u32 next0, next1, next2, next3;
1079 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1080 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1081 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1082 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1084 /* Prefetch next iteration. */
1086 vlib_buffer_t *p4, *p5, *p6, *p7;
1088 p4 = vlib_get_buffer (vm, from[4]);
1089 p5 = vlib_get_buffer (vm, from[5]);
1090 p6 = vlib_get_buffer (vm, from[6]);
1091 p7 = vlib_get_buffer (vm, from[7]);
1093 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1094 vlib_prefetch_buffer_header (p4, LOAD);
1095 vlib_prefetch_buffer_header (p5, LOAD);
1096 vlib_prefetch_buffer_header (p6, LOAD);
1097 vlib_prefetch_buffer_header (p7, LOAD);
1099 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1100 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1101 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1102 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1105 to_next[0] = bi0 = from[0];
1106 to_next[1] = bi1 = from[1];
1107 to_next[2] = bi2 = from[2];
1108 to_next[3] = bi3 = from[3];
1112 n_left_to_next -= 4;
1114 b0 = vlib_get_buffer (vm, bi0);
1115 b1 = vlib_get_buffer (vm, bi1);
1116 b2 = vlib_get_buffer (vm, bi2);
1117 b3 = vlib_get_buffer (vm, bi3);
1120 pool_elt_at_index (sm->sid_lists,
1121 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1123 pool_elt_at_index (sm->sid_lists,
1124 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1126 pool_elt_at_index (sm->sid_lists,
1127 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1129 pool_elt_at_index (sm->sid_lists,
1130 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1132 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1133 vec_len (sl0->rewrite));
1134 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1135 vec_len (sl1->rewrite));
1136 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1137 vec_len (sl2->rewrite));
1138 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1139 vec_len (sl3->rewrite));
1141 ip0_encap = vlib_buffer_get_current (b0);
1142 ip1_encap = vlib_buffer_get_current (b1);
1143 ip2_encap = vlib_buffer_get_current (b2);
1144 ip3_encap = vlib_buffer_get_current (b3);
1146 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1147 sl0->rewrite, vec_len (sl0->rewrite));
1148 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1149 sl1->rewrite, vec_len (sl1->rewrite));
1150 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1151 sl2->rewrite, vec_len (sl2->rewrite));
1152 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1153 sl3->rewrite, vec_len (sl3->rewrite));
1155 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1156 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1157 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1158 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1160 ip0 = vlib_buffer_get_current (b0);
1161 ip1 = vlib_buffer_get_current (b1);
1162 ip2 = vlib_buffer_get_current (b2);
1163 ip3 = vlib_buffer_get_current (b3);
1165 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1166 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1167 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1168 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1170 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1172 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1174 sr_policy_rewrite_trace_t *tr =
1175 vlib_add_trace (vm, node, b0, sizeof (*tr));
1176 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1177 sizeof (tr->src.as_u8));
1178 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1179 sizeof (tr->dst.as_u8));
1182 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1184 sr_policy_rewrite_trace_t *tr =
1185 vlib_add_trace (vm, node, b1, sizeof (*tr));
1186 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1187 sizeof (tr->src.as_u8));
1188 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1189 sizeof (tr->dst.as_u8));
1192 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1194 sr_policy_rewrite_trace_t *tr =
1195 vlib_add_trace (vm, node, b2, sizeof (*tr));
1196 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1197 sizeof (tr->src.as_u8));
1198 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1199 sizeof (tr->dst.as_u8));
1202 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1204 sr_policy_rewrite_trace_t *tr =
1205 vlib_add_trace (vm, node, b3, sizeof (*tr));
1206 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1207 sizeof (tr->src.as_u8));
1208 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1209 sizeof (tr->dst.as_u8));
1214 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1215 n_left_to_next, bi0, bi1, bi2, bi3,
1216 next0, next1, next2, next3);
1219 /* Single loop for potentially the last three packets */
1220 while (n_left_from > 0 && n_left_to_next > 0)
1224 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1226 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1233 n_left_to_next -= 1;
1234 b0 = vlib_get_buffer (vm, bi0);
1237 pool_elt_at_index (sm->sid_lists,
1238 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1239 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1240 vec_len (sl0->rewrite));
1242 ip0_encap = vlib_buffer_get_current (b0);
1244 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1245 sl0->rewrite, vec_len (sl0->rewrite));
1246 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1248 ip0 = vlib_buffer_get_current (b0);
1250 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1252 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1253 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1255 sr_policy_rewrite_trace_t *tr =
1256 vlib_add_trace (vm, node, b0, sizeof (*tr));
1257 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1258 sizeof (tr->src.as_u8));
1259 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1260 sizeof (tr->dst.as_u8));
1264 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1265 n_left_to_next, bi0, next0);
1268 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1271 /* Update counters */
1272 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1273 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1275 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1276 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1279 return from_frame->n_vectors;
1283 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1284 .function = sr_policy_rewrite_encaps,
1285 .name = "sr-pl-rewrite-encaps",
1286 .vector_size = sizeof (u32),
1287 .format_trace = format_sr_policy_rewrite_trace,
1288 .type = VLIB_NODE_TYPE_INTERNAL,
1289 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1290 .error_strings = sr_policy_rewrite_error_strings,
1291 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1293 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1294 foreach_sr_policy_rewrite_next
1301 * @brief IPv4 encapsulation processing as per RFC2473
1303 static_always_inline void
1304 encaps_processing_v4 (vlib_node_runtime_t * node,
1306 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1309 ip6_sr_header_t *sr0;
1313 /* Inner IPv4: Decrement TTL & update checksum */
1314 ip0_encap->ttl -= 1;
1315 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1316 checksum0 += checksum0 >= 0xffff;
1317 ip0_encap->checksum = checksum0;
1319 /* Outer IPv6: Update length, FL, proto */
1320 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1321 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1322 ip0->ip_version_traffic_class_and_flow_label =
1323 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1324 ((ip0_encap->tos & 0xFF) << 20));
1325 sr0 = (void *) (ip0 + 1);
1326 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1330 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1333 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1334 vlib_frame_t * from_frame)
1336 ip6_sr_main_t *sm = &sr_main;
1337 u32 n_left_from, next_index, *from, *to_next;
1339 from = vlib_frame_vector_args (from_frame);
1340 n_left_from = from_frame->n_vectors;
1342 next_index = node->cached_next_index;
1344 int encap_pkts = 0, bsid_pkts = 0;
1346 while (n_left_from > 0)
1350 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1353 while (n_left_from >= 8 && n_left_to_next >= 4)
1355 u32 bi0, bi1, bi2, bi3;
1356 vlib_buffer_t *b0, *b1, *b2, *b3;
1357 u32 next0, next1, next2, next3;
1358 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1359 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1360 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1361 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1363 /* Prefetch next iteration. */
1365 vlib_buffer_t *p4, *p5, *p6, *p7;
1367 p4 = vlib_get_buffer (vm, from[4]);
1368 p5 = vlib_get_buffer (vm, from[5]);
1369 p6 = vlib_get_buffer (vm, from[6]);
1370 p7 = vlib_get_buffer (vm, from[7]);
1372 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1373 vlib_prefetch_buffer_header (p4, LOAD);
1374 vlib_prefetch_buffer_header (p5, LOAD);
1375 vlib_prefetch_buffer_header (p6, LOAD);
1376 vlib_prefetch_buffer_header (p7, LOAD);
1378 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1379 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1380 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1381 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1384 to_next[0] = bi0 = from[0];
1385 to_next[1] = bi1 = from[1];
1386 to_next[2] = bi2 = from[2];
1387 to_next[3] = bi3 = from[3];
1391 n_left_to_next -= 4;
1393 b0 = vlib_get_buffer (vm, bi0);
1394 b1 = vlib_get_buffer (vm, bi1);
1395 b2 = vlib_get_buffer (vm, bi2);
1396 b3 = vlib_get_buffer (vm, bi3);
1399 pool_elt_at_index (sm->sid_lists,
1400 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1402 pool_elt_at_index (sm->sid_lists,
1403 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1405 pool_elt_at_index (sm->sid_lists,
1406 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1408 pool_elt_at_index (sm->sid_lists,
1409 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1410 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1411 vec_len (sl0->rewrite));
1412 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1413 vec_len (sl1->rewrite));
1414 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1415 vec_len (sl2->rewrite));
1416 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1417 vec_len (sl3->rewrite));
1419 ip0_encap = vlib_buffer_get_current (b0);
1420 ip1_encap = vlib_buffer_get_current (b1);
1421 ip2_encap = vlib_buffer_get_current (b2);
1422 ip3_encap = vlib_buffer_get_current (b3);
1424 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1425 sl0->rewrite, vec_len (sl0->rewrite));
1426 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1427 sl1->rewrite, vec_len (sl1->rewrite));
1428 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1429 sl2->rewrite, vec_len (sl2->rewrite));
1430 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1431 sl3->rewrite, vec_len (sl3->rewrite));
1433 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1434 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1435 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1436 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1438 ip0 = vlib_buffer_get_current (b0);
1439 ip1 = vlib_buffer_get_current (b1);
1440 ip2 = vlib_buffer_get_current (b2);
1441 ip3 = vlib_buffer_get_current (b3);
1443 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1444 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1445 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1446 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1448 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1450 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1452 sr_policy_rewrite_trace_t *tr =
1453 vlib_add_trace (vm, node, b0, sizeof (*tr));
1454 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1455 sizeof (tr->src.as_u8));
1456 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1457 sizeof (tr->dst.as_u8));
1460 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1462 sr_policy_rewrite_trace_t *tr =
1463 vlib_add_trace (vm, node, b1, sizeof (*tr));
1464 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1465 sizeof (tr->src.as_u8));
1466 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1467 sizeof (tr->dst.as_u8));
1470 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1472 sr_policy_rewrite_trace_t *tr =
1473 vlib_add_trace (vm, node, b2, sizeof (*tr));
1474 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1475 sizeof (tr->src.as_u8));
1476 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1477 sizeof (tr->dst.as_u8));
1480 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1482 sr_policy_rewrite_trace_t *tr =
1483 vlib_add_trace (vm, node, b3, sizeof (*tr));
1484 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1485 sizeof (tr->src.as_u8));
1486 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1487 sizeof (tr->dst.as_u8));
1492 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1493 n_left_to_next, bi0, bi1, bi2, bi3,
1494 next0, next1, next2, next3);
1497 /* Single loop for potentially the last three packets */
1498 while (n_left_from > 0 && n_left_to_next > 0)
1502 ip6_header_t *ip0 = 0;
1503 ip4_header_t *ip0_encap = 0;
1505 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1512 n_left_to_next -= 1;
1513 b0 = vlib_get_buffer (vm, bi0);
1516 pool_elt_at_index (sm->sid_lists,
1517 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1518 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1519 vec_len (sl0->rewrite));
1521 ip0_encap = vlib_buffer_get_current (b0);
1523 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1524 sl0->rewrite, vec_len (sl0->rewrite));
1525 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1527 ip0 = vlib_buffer_get_current (b0);
1529 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1531 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1532 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1534 sr_policy_rewrite_trace_t *tr =
1535 vlib_add_trace (vm, node, b0, sizeof (*tr));
1536 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1537 sizeof (tr->src.as_u8));
1538 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1539 sizeof (tr->dst.as_u8));
1543 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1544 n_left_to_next, bi0, next0);
1547 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1550 /* Update counters */
1551 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1552 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1554 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1555 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1558 return from_frame->n_vectors;
1562 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1563 .function = sr_policy_rewrite_encaps_v4,
1564 .name = "sr-pl-rewrite-encaps-v4",
1565 .vector_size = sizeof (u32),
1566 .format_trace = format_sr_policy_rewrite_trace,
1567 .type = VLIB_NODE_TYPE_INTERNAL,
1568 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1569 .error_strings = sr_policy_rewrite_error_strings,
1570 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1572 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1573 foreach_sr_policy_rewrite_next
1580 ip_flow_hash (void *data)
1582 ip4_header_t *iph = (ip4_header_t *) data;
1584 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1585 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1587 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1593 return (*((u64 *) m) & 0xffffffffffff);
1597 l2_flow_hash (vlib_buffer_t * b0)
1599 ethernet_header_t *eh;
1601 uword is_ip, eh_size;
1604 eh = vlib_buffer_get_current (b0);
1605 eh_type = clib_net_to_host_u16 (eh->type);
1606 eh_size = ethernet_buffer_header_size (b0);
1608 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1610 /* since we have 2 cache lines, use them */
1612 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1616 b = mac_to_u64 ((u8 *) eh->dst_address);
1617 c = mac_to_u64 ((u8 *) eh->src_address);
1618 hash_mix64 (a, b, c);
1624 * @brief Graph node for applying a SR policy into a L2 frame
1627 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1628 vlib_frame_t * from_frame)
1630 ip6_sr_main_t *sm = &sr_main;
1631 u32 n_left_from, next_index, *from, *to_next;
1633 from = vlib_frame_vector_args (from_frame);
1634 n_left_from = from_frame->n_vectors;
1636 next_index = node->cached_next_index;
1638 int encap_pkts = 0, bsid_pkts = 0;
1640 while (n_left_from > 0)
1644 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1647 while (n_left_from >= 8 && n_left_to_next >= 4)
1649 u32 bi0, bi1, bi2, bi3;
1650 vlib_buffer_t *b0, *b1, *b2, *b3;
1651 u32 next0, next1, next2, next3;
1652 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1653 ethernet_header_t *en0, *en1, *en2, *en3;
1654 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1655 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1656 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1657 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1659 /* Prefetch next iteration. */
1661 vlib_buffer_t *p4, *p5, *p6, *p7;
1663 p4 = vlib_get_buffer (vm, from[4]);
1664 p5 = vlib_get_buffer (vm, from[5]);
1665 p6 = vlib_get_buffer (vm, from[6]);
1666 p7 = vlib_get_buffer (vm, from[7]);
1668 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1669 vlib_prefetch_buffer_header (p4, LOAD);
1670 vlib_prefetch_buffer_header (p5, LOAD);
1671 vlib_prefetch_buffer_header (p6, LOAD);
1672 vlib_prefetch_buffer_header (p7, LOAD);
1674 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1675 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1676 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1677 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1680 to_next[0] = bi0 = from[0];
1681 to_next[1] = bi1 = from[1];
1682 to_next[2] = bi2 = from[2];
1683 to_next[3] = bi3 = from[3];
1687 n_left_to_next -= 4;
1689 b0 = vlib_get_buffer (vm, bi0);
1690 b1 = vlib_get_buffer (vm, bi1);
1691 b2 = vlib_get_buffer (vm, bi2);
1692 b3 = vlib_get_buffer (vm, bi3);
1694 sp0 = pool_elt_at_index (sm->sr_policies,
1695 sm->sw_iface_sr_policies[vnet_buffer
1699 sp1 = pool_elt_at_index (sm->sr_policies,
1700 sm->sw_iface_sr_policies[vnet_buffer
1704 sp2 = pool_elt_at_index (sm->sr_policies,
1705 sm->sw_iface_sr_policies[vnet_buffer
1709 sp3 = pool_elt_at_index (sm->sr_policies,
1710 sm->sw_iface_sr_policies[vnet_buffer
1714 if (vec_len (sp0->segments_lists) == 1)
1715 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1718 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1719 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1720 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1721 (vec_len (sp0->segments_lists) - 1))];
1724 if (vec_len (sp1->segments_lists) == 1)
1725 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1728 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1729 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1730 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1731 (vec_len (sp1->segments_lists) - 1))];
1734 if (vec_len (sp2->segments_lists) == 1)
1735 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1738 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1739 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1740 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1741 (vec_len (sp2->segments_lists) - 1))];
1744 if (vec_len (sp3->segments_lists) == 1)
1745 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1748 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1749 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1750 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1751 (vec_len (sp3->segments_lists) - 1))];
1755 pool_elt_at_index (sm->sid_lists,
1756 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1758 pool_elt_at_index (sm->sid_lists,
1759 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1761 pool_elt_at_index (sm->sid_lists,
1762 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1764 pool_elt_at_index (sm->sid_lists,
1765 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1767 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1768 vec_len (sl0->rewrite));
1769 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1770 vec_len (sl1->rewrite));
1771 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1772 vec_len (sl2->rewrite));
1773 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1774 vec_len (sl3->rewrite));
1776 en0 = vlib_buffer_get_current (b0);
1777 en1 = vlib_buffer_get_current (b1);
1778 en2 = vlib_buffer_get_current (b2);
1779 en3 = vlib_buffer_get_current (b3);
1781 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1782 vec_len (sl0->rewrite));
1783 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1784 vec_len (sl1->rewrite));
1785 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1786 vec_len (sl2->rewrite));
1787 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1788 vec_len (sl3->rewrite));
1790 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1791 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1792 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1793 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1795 ip0 = vlib_buffer_get_current (b0);
1796 ip1 = vlib_buffer_get_current (b1);
1797 ip2 = vlib_buffer_get_current (b2);
1798 ip3 = vlib_buffer_get_current (b3);
1800 ip0->payload_length =
1801 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1802 ip1->payload_length =
1803 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1804 ip2->payload_length =
1805 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1806 ip3->payload_length =
1807 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1809 sr0 = (void *) (ip0 + 1);
1810 sr1 = (void *) (ip1 + 1);
1811 sr2 = (void *) (ip2 + 1);
1812 sr3 = (void *) (ip3 + 1);
1814 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1815 IP_PROTOCOL_IP6_NONXT;
1817 /* Which Traffic class and flow label do I set ? */
1818 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1820 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1822 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1824 sr_policy_rewrite_trace_t *tr =
1825 vlib_add_trace (vm, node, b0, sizeof (*tr));
1826 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1827 sizeof (tr->src.as_u8));
1828 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1829 sizeof (tr->dst.as_u8));
1832 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1834 sr_policy_rewrite_trace_t *tr =
1835 vlib_add_trace (vm, node, b1, sizeof (*tr));
1836 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1837 sizeof (tr->src.as_u8));
1838 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1839 sizeof (tr->dst.as_u8));
1842 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1844 sr_policy_rewrite_trace_t *tr =
1845 vlib_add_trace (vm, node, b2, sizeof (*tr));
1846 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1847 sizeof (tr->src.as_u8));
1848 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1849 sizeof (tr->dst.as_u8));
1852 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1854 sr_policy_rewrite_trace_t *tr =
1855 vlib_add_trace (vm, node, b3, sizeof (*tr));
1856 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1857 sizeof (tr->src.as_u8));
1858 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1859 sizeof (tr->dst.as_u8));
1864 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1865 n_left_to_next, bi0, bi1, bi2, bi3,
1866 next0, next1, next2, next3);
1869 /* Single loop for potentially the last three packets */
1870 while (n_left_from > 0 && n_left_to_next > 0)
1874 ip6_header_t *ip0 = 0;
1875 ip6_sr_header_t *sr0;
1876 ethernet_header_t *en0;
1877 ip6_sr_policy_t *sp0;
1879 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1886 n_left_to_next -= 1;
1887 b0 = vlib_get_buffer (vm, bi0);
1889 /* Find the SR policy */
1890 sp0 = pool_elt_at_index (sm->sr_policies,
1891 sm->sw_iface_sr_policies[vnet_buffer
1895 /* In case there is more than one SL, LB among them */
1896 if (vec_len (sp0->segments_lists) == 1)
1897 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1900 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1901 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1902 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1903 (vec_len (sp0->segments_lists) - 1))];
1906 pool_elt_at_index (sm->sid_lists,
1907 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1908 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1909 vec_len (sl0->rewrite));
1911 en0 = vlib_buffer_get_current (b0);
1913 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1914 vec_len (sl0->rewrite));
1916 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1918 ip0 = vlib_buffer_get_current (b0);
1920 ip0->payload_length =
1921 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1923 sr0 = (void *) (ip0 + 1);
1924 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1926 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1927 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1929 sr_policy_rewrite_trace_t *tr =
1930 vlib_add_trace (vm, node, b0, sizeof (*tr));
1931 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1932 sizeof (tr->src.as_u8));
1933 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1934 sizeof (tr->dst.as_u8));
1938 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1939 n_left_to_next, bi0, next0);
1942 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1945 /* Update counters */
1946 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1947 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1949 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1950 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1953 return from_frame->n_vectors;
1957 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1958 .function = sr_policy_rewrite_encaps_l2,
1959 .name = "sr-pl-rewrite-encaps-l2",
1960 .vector_size = sizeof (u32),
1961 .format_trace = format_sr_policy_rewrite_trace,
1962 .type = VLIB_NODE_TYPE_INTERNAL,
1963 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1964 .error_strings = sr_policy_rewrite_error_strings,
1965 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1967 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1968 foreach_sr_policy_rewrite_next
1975 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1978 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1979 vlib_frame_t * from_frame)
1981 ip6_sr_main_t *sm = &sr_main;
1982 u32 n_left_from, next_index, *from, *to_next;
1984 from = vlib_frame_vector_args (from_frame);
1985 n_left_from = from_frame->n_vectors;
1987 next_index = node->cached_next_index;
1989 int insert_pkts = 0, bsid_pkts = 0;
1991 while (n_left_from > 0)
1995 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1998 while (n_left_from >= 8 && n_left_to_next >= 4)
2000 u32 bi0, bi1, bi2, bi3;
2001 vlib_buffer_t *b0, *b1, *b2, *b3;
2002 u32 next0, next1, next2, next3;
2003 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2004 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2005 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2006 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2007 u16 new_l0, new_l1, new_l2, new_l3;
2009 /* Prefetch next iteration. */
2011 vlib_buffer_t *p4, *p5, *p6, *p7;
2013 p4 = vlib_get_buffer (vm, from[4]);
2014 p5 = vlib_get_buffer (vm, from[5]);
2015 p6 = vlib_get_buffer (vm, from[6]);
2016 p7 = vlib_get_buffer (vm, from[7]);
2018 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2019 vlib_prefetch_buffer_header (p4, LOAD);
2020 vlib_prefetch_buffer_header (p5, LOAD);
2021 vlib_prefetch_buffer_header (p6, LOAD);
2022 vlib_prefetch_buffer_header (p7, LOAD);
2024 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2025 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2026 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2027 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2030 to_next[0] = bi0 = from[0];
2031 to_next[1] = bi1 = from[1];
2032 to_next[2] = bi2 = from[2];
2033 to_next[3] = bi3 = from[3];
2037 n_left_to_next -= 4;
2039 b0 = vlib_get_buffer (vm, bi0);
2040 b1 = vlib_get_buffer (vm, bi1);
2041 b2 = vlib_get_buffer (vm, bi2);
2042 b3 = vlib_get_buffer (vm, bi3);
2045 pool_elt_at_index (sm->sid_lists,
2046 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2048 pool_elt_at_index (sm->sid_lists,
2049 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2051 pool_elt_at_index (sm->sid_lists,
2052 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2054 pool_elt_at_index (sm->sid_lists,
2055 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2056 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2057 vec_len (sl0->rewrite));
2058 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2059 vec_len (sl1->rewrite));
2060 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2061 vec_len (sl2->rewrite));
2062 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2063 vec_len (sl3->rewrite));
2065 ip0 = vlib_buffer_get_current (b0);
2066 ip1 = vlib_buffer_get_current (b1);
2067 ip2 = vlib_buffer_get_current (b2);
2068 ip3 = vlib_buffer_get_current (b3);
2070 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2072 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2073 ip6_ext_header_len (ip0 + 1));
2075 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2077 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2079 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2080 ip6_ext_header_len (ip1 + 1));
2082 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2084 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2086 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2087 ip6_ext_header_len (ip2 + 1));
2089 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2091 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2093 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2094 ip6_ext_header_len (ip3 + 1));
2096 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2098 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2099 (void *) sr0 - (void *) ip0);
2100 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2101 (void *) sr1 - (void *) ip1);
2102 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2103 (void *) sr2 - (void *) ip2);
2104 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2105 (void *) sr3 - (void *) ip3);
2107 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2108 vec_len (sl0->rewrite));
2109 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2110 vec_len (sl1->rewrite));
2111 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2112 vec_len (sl2->rewrite));
2113 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2114 vec_len (sl3->rewrite));
2116 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2117 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2118 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2119 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2121 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2122 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2123 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2124 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2126 ip0->hop_limit -= 1;
2127 ip1->hop_limit -= 1;
2128 ip2->hop_limit -= 1;
2129 ip3->hop_limit -= 1;
2132 clib_net_to_host_u16 (ip0->payload_length) +
2133 vec_len (sl0->rewrite);
2135 clib_net_to_host_u16 (ip1->payload_length) +
2136 vec_len (sl1->rewrite);
2138 clib_net_to_host_u16 (ip2->payload_length) +
2139 vec_len (sl2->rewrite);
2141 clib_net_to_host_u16 (ip3->payload_length) +
2142 vec_len (sl3->rewrite);
2144 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2145 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2146 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2147 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2149 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2150 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2151 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2152 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2154 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2155 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2156 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2157 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2158 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2159 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2160 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2161 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2163 ip0->dst_address.as_u64[0] =
2164 (sr0->segments + sr0->segments_left)->as_u64[0];
2165 ip0->dst_address.as_u64[1] =
2166 (sr0->segments + sr0->segments_left)->as_u64[1];
2167 ip1->dst_address.as_u64[0] =
2168 (sr1->segments + sr1->segments_left)->as_u64[0];
2169 ip1->dst_address.as_u64[1] =
2170 (sr1->segments + sr1->segments_left)->as_u64[1];
2171 ip2->dst_address.as_u64[0] =
2172 (sr2->segments + sr2->segments_left)->as_u64[0];
2173 ip2->dst_address.as_u64[1] =
2174 (sr2->segments + sr2->segments_left)->as_u64[1];
2175 ip3->dst_address.as_u64[0] =
2176 (sr3->segments + sr3->segments_left)->as_u64[0];
2177 ip3->dst_address.as_u64[1] =
2178 (sr3->segments + sr3->segments_left)->as_u64[1];
2180 ip6_ext_header_t *ip_ext;
2181 if (ip0 + 1 == (void *) sr0)
2183 sr0->protocol = ip0->protocol;
2184 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2188 ip_ext = (void *) (ip0 + 1);
2189 sr0->protocol = ip_ext->next_hdr;
2190 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2193 if (ip1 + 1 == (void *) sr1)
2195 sr1->protocol = ip1->protocol;
2196 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2200 ip_ext = (void *) (ip2 + 1);
2201 sr2->protocol = ip_ext->next_hdr;
2202 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2205 if (ip2 + 1 == (void *) sr2)
2207 sr2->protocol = ip2->protocol;
2208 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2212 ip_ext = (void *) (ip2 + 1);
2213 sr2->protocol = ip_ext->next_hdr;
2214 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2217 if (ip3 + 1 == (void *) sr3)
2219 sr3->protocol = ip3->protocol;
2220 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2224 ip_ext = (void *) (ip3 + 1);
2225 sr3->protocol = ip_ext->next_hdr;
2226 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2231 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2233 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2235 sr_policy_rewrite_trace_t *tr =
2236 vlib_add_trace (vm, node, b0, sizeof (*tr));
2237 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2238 sizeof (tr->src.as_u8));
2239 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2240 sizeof (tr->dst.as_u8));
2243 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2245 sr_policy_rewrite_trace_t *tr =
2246 vlib_add_trace (vm, node, b1, sizeof (*tr));
2247 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2248 sizeof (tr->src.as_u8));
2249 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2250 sizeof (tr->dst.as_u8));
2253 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2255 sr_policy_rewrite_trace_t *tr =
2256 vlib_add_trace (vm, node, b2, sizeof (*tr));
2257 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2258 sizeof (tr->src.as_u8));
2259 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2260 sizeof (tr->dst.as_u8));
2263 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2265 sr_policy_rewrite_trace_t *tr =
2266 vlib_add_trace (vm, node, b3, sizeof (*tr));
2267 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2268 sizeof (tr->src.as_u8));
2269 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2270 sizeof (tr->dst.as_u8));
2274 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2275 n_left_to_next, bi0, bi1, bi2, bi3,
2276 next0, next1, next2, next3);
2279 /* Single loop for potentially the last three packets */
2280 while (n_left_from > 0 && n_left_to_next > 0)
2284 ip6_header_t *ip0 = 0;
2285 ip6_sr_header_t *sr0 = 0;
2287 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2295 n_left_to_next -= 1;
2297 b0 = vlib_get_buffer (vm, bi0);
2299 pool_elt_at_index (sm->sid_lists,
2300 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2301 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2302 vec_len (sl0->rewrite));
2304 ip0 = vlib_buffer_get_current (b0);
2306 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2308 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2309 ip6_ext_header_len (ip0 + 1));
2311 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2313 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2314 (void *) sr0 - (void *) ip0);
2315 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2316 vec_len (sl0->rewrite));
2318 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2320 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2321 ip0->hop_limit -= 1;
2323 clib_net_to_host_u16 (ip0->payload_length) +
2324 vec_len (sl0->rewrite);
2325 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2327 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2328 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2329 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2331 ip0->dst_address.as_u64[0] =
2332 (sr0->segments + sr0->segments_left)->as_u64[0];
2333 ip0->dst_address.as_u64[1] =
2334 (sr0->segments + sr0->segments_left)->as_u64[1];
2336 if (ip0 + 1 == (void *) sr0)
2338 sr0->protocol = ip0->protocol;
2339 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2343 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2344 sr0->protocol = ip_ext->next_hdr;
2345 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2348 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2349 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2351 sr_policy_rewrite_trace_t *tr =
2352 vlib_add_trace (vm, node, b0, sizeof (*tr));
2353 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2354 sizeof (tr->src.as_u8));
2355 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2356 sizeof (tr->dst.as_u8));
2361 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2362 n_left_to_next, bi0, next0);
2365 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2368 /* Update counters */
2369 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2370 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2372 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2373 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2375 return from_frame->n_vectors;
2379 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2380 .function = sr_policy_rewrite_insert,
2381 .name = "sr-pl-rewrite-insert",
2382 .vector_size = sizeof (u32),
2383 .format_trace = format_sr_policy_rewrite_trace,
2384 .type = VLIB_NODE_TYPE_INTERNAL,
2385 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2386 .error_strings = sr_policy_rewrite_error_strings,
2387 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2389 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2390 foreach_sr_policy_rewrite_next
2397 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2400 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2401 vlib_frame_t * from_frame)
2403 ip6_sr_main_t *sm = &sr_main;
2404 u32 n_left_from, next_index, *from, *to_next;
2406 from = vlib_frame_vector_args (from_frame);
2407 n_left_from = from_frame->n_vectors;
2409 next_index = node->cached_next_index;
2411 int insert_pkts = 0, bsid_pkts = 0;
2413 while (n_left_from > 0)
2417 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2420 while (n_left_from >= 8 && n_left_to_next >= 4)
2422 u32 bi0, bi1, bi2, bi3;
2423 vlib_buffer_t *b0, *b1, *b2, *b3;
2424 u32 next0, next1, next2, next3;
2425 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2426 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2427 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2428 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2429 u16 new_l0, new_l1, new_l2, new_l3;
2431 /* Prefetch next iteration. */
2433 vlib_buffer_t *p4, *p5, *p6, *p7;
2435 p4 = vlib_get_buffer (vm, from[4]);
2436 p5 = vlib_get_buffer (vm, from[5]);
2437 p6 = vlib_get_buffer (vm, from[6]);
2438 p7 = vlib_get_buffer (vm, from[7]);
2440 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2441 vlib_prefetch_buffer_header (p4, LOAD);
2442 vlib_prefetch_buffer_header (p5, LOAD);
2443 vlib_prefetch_buffer_header (p6, LOAD);
2444 vlib_prefetch_buffer_header (p7, LOAD);
2446 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2447 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2448 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2449 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2452 to_next[0] = bi0 = from[0];
2453 to_next[1] = bi1 = from[1];
2454 to_next[2] = bi2 = from[2];
2455 to_next[3] = bi3 = from[3];
2459 n_left_to_next -= 4;
2461 b0 = vlib_get_buffer (vm, bi0);
2462 b1 = vlib_get_buffer (vm, bi1);
2463 b2 = vlib_get_buffer (vm, bi2);
2464 b3 = vlib_get_buffer (vm, bi3);
2467 pool_elt_at_index (sm->sid_lists,
2468 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2470 pool_elt_at_index (sm->sid_lists,
2471 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2473 pool_elt_at_index (sm->sid_lists,
2474 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2476 pool_elt_at_index (sm->sid_lists,
2477 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2478 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2479 vec_len (sl0->rewrite_bsid));
2480 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2481 vec_len (sl1->rewrite_bsid));
2482 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2483 vec_len (sl2->rewrite_bsid));
2484 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2485 vec_len (sl3->rewrite_bsid));
2487 ip0 = vlib_buffer_get_current (b0);
2488 ip1 = vlib_buffer_get_current (b1);
2489 ip2 = vlib_buffer_get_current (b2);
2490 ip3 = vlib_buffer_get_current (b3);
2492 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2494 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2495 ip6_ext_header_len (ip0 + 1));
2497 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2499 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2501 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2502 ip6_ext_header_len (ip1 + 1));
2504 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2506 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2508 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2509 ip6_ext_header_len (ip2 + 1));
2511 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2513 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2515 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2516 ip6_ext_header_len (ip3 + 1));
2518 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2520 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2521 (void *) sr0 - (void *) ip0);
2522 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2523 (void *) sr1 - (void *) ip1);
2524 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2525 (void *) sr2 - (void *) ip2);
2526 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2527 (void *) sr3 - (void *) ip3);
2529 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2530 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2531 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2532 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2533 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2534 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2535 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2536 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2538 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2539 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2540 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2541 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2543 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2544 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2545 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2546 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2548 ip0->hop_limit -= 1;
2549 ip1->hop_limit -= 1;
2550 ip2->hop_limit -= 1;
2551 ip3->hop_limit -= 1;
2554 clib_net_to_host_u16 (ip0->payload_length) +
2555 vec_len (sl0->rewrite_bsid);
2557 clib_net_to_host_u16 (ip1->payload_length) +
2558 vec_len (sl1->rewrite_bsid);
2560 clib_net_to_host_u16 (ip2->payload_length) +
2561 vec_len (sl2->rewrite_bsid);
2563 clib_net_to_host_u16 (ip3->payload_length) +
2564 vec_len (sl3->rewrite_bsid);
2566 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2567 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2568 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2569 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2571 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2572 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2573 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2574 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2576 ip0->dst_address.as_u64[0] =
2577 (sr0->segments + sr0->segments_left)->as_u64[0];
2578 ip0->dst_address.as_u64[1] =
2579 (sr0->segments + sr0->segments_left)->as_u64[1];
2580 ip1->dst_address.as_u64[0] =
2581 (sr1->segments + sr1->segments_left)->as_u64[0];
2582 ip1->dst_address.as_u64[1] =
2583 (sr1->segments + sr1->segments_left)->as_u64[1];
2584 ip2->dst_address.as_u64[0] =
2585 (sr2->segments + sr2->segments_left)->as_u64[0];
2586 ip2->dst_address.as_u64[1] =
2587 (sr2->segments + sr2->segments_left)->as_u64[1];
2588 ip3->dst_address.as_u64[0] =
2589 (sr3->segments + sr3->segments_left)->as_u64[0];
2590 ip3->dst_address.as_u64[1] =
2591 (sr3->segments + sr3->segments_left)->as_u64[1];
2593 ip6_ext_header_t *ip_ext;
2594 if (ip0 + 1 == (void *) sr0)
2596 sr0->protocol = ip0->protocol;
2597 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2601 ip_ext = (void *) (ip0 + 1);
2602 sr0->protocol = ip_ext->next_hdr;
2603 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2606 if (ip1 + 1 == (void *) sr1)
2608 sr1->protocol = ip1->protocol;
2609 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2613 ip_ext = (void *) (ip2 + 1);
2614 sr2->protocol = ip_ext->next_hdr;
2615 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2618 if (ip2 + 1 == (void *) sr2)
2620 sr2->protocol = ip2->protocol;
2621 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2625 ip_ext = (void *) (ip2 + 1);
2626 sr2->protocol = ip_ext->next_hdr;
2627 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2630 if (ip3 + 1 == (void *) sr3)
2632 sr3->protocol = ip3->protocol;
2633 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2637 ip_ext = (void *) (ip3 + 1);
2638 sr3->protocol = ip_ext->next_hdr;
2639 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2644 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2646 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2648 sr_policy_rewrite_trace_t *tr =
2649 vlib_add_trace (vm, node, b0, sizeof (*tr));
2650 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2651 sizeof (tr->src.as_u8));
2652 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2653 sizeof (tr->dst.as_u8));
2656 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2658 sr_policy_rewrite_trace_t *tr =
2659 vlib_add_trace (vm, node, b1, sizeof (*tr));
2660 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2661 sizeof (tr->src.as_u8));
2662 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2663 sizeof (tr->dst.as_u8));
2666 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2668 sr_policy_rewrite_trace_t *tr =
2669 vlib_add_trace (vm, node, b2, sizeof (*tr));
2670 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2671 sizeof (tr->src.as_u8));
2672 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2673 sizeof (tr->dst.as_u8));
2676 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2678 sr_policy_rewrite_trace_t *tr =
2679 vlib_add_trace (vm, node, b3, sizeof (*tr));
2680 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2681 sizeof (tr->src.as_u8));
2682 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2683 sizeof (tr->dst.as_u8));
2687 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2688 n_left_to_next, bi0, bi1, bi2, bi3,
2689 next0, next1, next2, next3);
2692 /* Single loop for potentially the last three packets */
2693 while (n_left_from > 0 && n_left_to_next > 0)
2697 ip6_header_t *ip0 = 0;
2698 ip6_sr_header_t *sr0 = 0;
2700 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2708 n_left_to_next -= 1;
2710 b0 = vlib_get_buffer (vm, bi0);
2712 pool_elt_at_index (sm->sid_lists,
2713 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2714 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2715 vec_len (sl0->rewrite_bsid));
2717 ip0 = vlib_buffer_get_current (b0);
2719 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2721 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2722 ip6_ext_header_len (ip0 + 1));
2724 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2726 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2727 (void *) sr0 - (void *) ip0);
2728 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2729 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2731 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2733 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2734 ip0->hop_limit -= 1;
2736 clib_net_to_host_u16 (ip0->payload_length) +
2737 vec_len (sl0->rewrite_bsid);
2738 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2740 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2742 ip0->dst_address.as_u64[0] =
2743 (sr0->segments + sr0->segments_left)->as_u64[0];
2744 ip0->dst_address.as_u64[1] =
2745 (sr0->segments + sr0->segments_left)->as_u64[1];
2747 if (ip0 + 1 == (void *) sr0)
2749 sr0->protocol = ip0->protocol;
2750 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2754 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2755 sr0->protocol = ip_ext->next_hdr;
2756 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2759 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2760 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2762 sr_policy_rewrite_trace_t *tr =
2763 vlib_add_trace (vm, node, b0, sizeof (*tr));
2764 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2765 sizeof (tr->src.as_u8));
2766 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2767 sizeof (tr->dst.as_u8));
2772 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2773 n_left_to_next, bi0, next0);
2776 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2779 /* Update counters */
2780 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2781 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2783 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2784 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2786 return from_frame->n_vectors;
2790 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2791 .function = sr_policy_rewrite_b_insert,
2792 .name = "sr-pl-rewrite-b-insert",
2793 .vector_size = sizeof (u32),
2794 .format_trace = format_sr_policy_rewrite_trace,
2795 .type = VLIB_NODE_TYPE_INTERNAL,
2796 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2797 .error_strings = sr_policy_rewrite_error_strings,
2798 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2800 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2801 foreach_sr_policy_rewrite_next
2808 * @brief Function BSID encapsulation
2810 static_always_inline void
2811 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2814 ip6_sr_header_t * sr0, u32 * next0)
2816 ip6_address_t *new_dst0;
2818 if (PREDICT_FALSE (!sr0))
2819 goto error_bsid_encaps;
2821 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2823 if (PREDICT_TRUE (sr0->segments_left != 0))
2825 sr0->segments_left -= 1;
2826 new_dst0 = (ip6_address_t *) (sr0->segments);
2827 new_dst0 += sr0->segments_left;
2828 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2829 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2835 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2836 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2840 * @brief Graph node for applying a SR policy BSID - Encapsulation
2843 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2844 vlib_frame_t * from_frame)
2846 ip6_sr_main_t *sm = &sr_main;
2847 u32 n_left_from, next_index, *from, *to_next;
2849 from = vlib_frame_vector_args (from_frame);
2850 n_left_from = from_frame->n_vectors;
2852 next_index = node->cached_next_index;
2854 int encap_pkts = 0, bsid_pkts = 0;
2856 while (n_left_from > 0)
2860 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2863 while (n_left_from >= 8 && n_left_to_next >= 4)
2865 u32 bi0, bi1, bi2, bi3;
2866 vlib_buffer_t *b0, *b1, *b2, *b3;
2867 u32 next0, next1, next2, next3;
2868 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2869 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2870 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2871 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2872 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2873 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2875 /* Prefetch next iteration. */
2877 vlib_buffer_t *p4, *p5, *p6, *p7;
2879 p4 = vlib_get_buffer (vm, from[4]);
2880 p5 = vlib_get_buffer (vm, from[5]);
2881 p6 = vlib_get_buffer (vm, from[6]);
2882 p7 = vlib_get_buffer (vm, from[7]);
2884 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2885 vlib_prefetch_buffer_header (p4, LOAD);
2886 vlib_prefetch_buffer_header (p5, LOAD);
2887 vlib_prefetch_buffer_header (p6, LOAD);
2888 vlib_prefetch_buffer_header (p7, LOAD);
2890 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2891 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2892 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2893 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2896 to_next[0] = bi0 = from[0];
2897 to_next[1] = bi1 = from[1];
2898 to_next[2] = bi2 = from[2];
2899 to_next[3] = bi3 = from[3];
2903 n_left_to_next -= 4;
2905 b0 = vlib_get_buffer (vm, bi0);
2906 b1 = vlib_get_buffer (vm, bi1);
2907 b2 = vlib_get_buffer (vm, bi2);
2908 b3 = vlib_get_buffer (vm, bi3);
2911 pool_elt_at_index (sm->sid_lists,
2912 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2914 pool_elt_at_index (sm->sid_lists,
2915 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2917 pool_elt_at_index (sm->sid_lists,
2918 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2920 pool_elt_at_index (sm->sid_lists,
2921 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2922 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2923 vec_len (sl0->rewrite));
2924 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2925 vec_len (sl1->rewrite));
2926 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2927 vec_len (sl2->rewrite));
2928 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929 vec_len (sl3->rewrite));
2931 ip0_encap = vlib_buffer_get_current (b0);
2932 ip1_encap = vlib_buffer_get_current (b1);
2933 ip2_encap = vlib_buffer_get_current (b2);
2934 ip3_encap = vlib_buffer_get_current (b3);
2936 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2937 IP_PROTOCOL_IPV6_ROUTE);
2938 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2939 IP_PROTOCOL_IPV6_ROUTE);
2940 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2941 IP_PROTOCOL_IPV6_ROUTE);
2942 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2943 IP_PROTOCOL_IPV6_ROUTE);
2945 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2946 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2947 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2948 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2950 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2951 sl0->rewrite, vec_len (sl0->rewrite));
2952 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2953 sl1->rewrite, vec_len (sl1->rewrite));
2954 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2955 sl2->rewrite, vec_len (sl2->rewrite));
2956 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2957 sl3->rewrite, vec_len (sl3->rewrite));
2959 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2960 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2961 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2962 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2964 ip0 = vlib_buffer_get_current (b0);
2965 ip1 = vlib_buffer_get_current (b1);
2966 ip2 = vlib_buffer_get_current (b2);
2967 ip3 = vlib_buffer_get_current (b3);
2969 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2970 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2971 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2972 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2974 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2976 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2978 sr_policy_rewrite_trace_t *tr =
2979 vlib_add_trace (vm, node, b0, sizeof (*tr));
2980 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2981 sizeof (tr->src.as_u8));
2982 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2983 sizeof (tr->dst.as_u8));
2986 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2988 sr_policy_rewrite_trace_t *tr =
2989 vlib_add_trace (vm, node, b1, sizeof (*tr));
2990 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2991 sizeof (tr->src.as_u8));
2992 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2993 sizeof (tr->dst.as_u8));
2996 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2998 sr_policy_rewrite_trace_t *tr =
2999 vlib_add_trace (vm, node, b2, sizeof (*tr));
3000 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3001 sizeof (tr->src.as_u8));
3002 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3003 sizeof (tr->dst.as_u8));
3006 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3008 sr_policy_rewrite_trace_t *tr =
3009 vlib_add_trace (vm, node, b3, sizeof (*tr));
3010 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3011 sizeof (tr->src.as_u8));
3012 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3013 sizeof (tr->dst.as_u8));
3018 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3019 n_left_to_next, bi0, bi1, bi2, bi3,
3020 next0, next1, next2, next3);
3023 /* Single loop for potentially the last three packets */
3024 while (n_left_from > 0 && n_left_to_next > 0)
3028 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3029 ip6_ext_header_t *prev0;
3030 ip6_sr_header_t *sr0;
3032 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3039 n_left_to_next -= 1;
3040 b0 = vlib_get_buffer (vm, bi0);
3043 pool_elt_at_index (sm->sid_lists,
3044 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3045 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3046 vec_len (sl0->rewrite));
3048 ip0_encap = vlib_buffer_get_current (b0);
3049 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3050 IP_PROTOCOL_IPV6_ROUTE);
3051 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3053 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3054 sl0->rewrite, vec_len (sl0->rewrite));
3055 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3057 ip0 = vlib_buffer_get_current (b0);
3059 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3061 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3062 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3064 sr_policy_rewrite_trace_t *tr =
3065 vlib_add_trace (vm, node, b0, sizeof (*tr));
3066 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3067 sizeof (tr->src.as_u8));
3068 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3069 sizeof (tr->dst.as_u8));
3073 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3074 n_left_to_next, bi0, next0);
3077 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3080 /* Update counters */
3081 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3082 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3084 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3085 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3088 return from_frame->n_vectors;
3092 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3093 .function = sr_policy_rewrite_b_encaps,
3094 .name = "sr-pl-rewrite-b-encaps",
3095 .vector_size = sizeof (u32),
3096 .format_trace = format_sr_policy_rewrite_trace,
3097 .type = VLIB_NODE_TYPE_INTERNAL,
3098 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3099 .error_strings = sr_policy_rewrite_error_strings,
3100 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3102 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3103 foreach_sr_policy_rewrite_next
3109 /*************************** SR Segment Lists DPOs ****************************/
3111 format_sr_segment_list_dpo (u8 * s, va_list * args)
3113 ip6_sr_main_t *sm = &sr_main;
3114 ip6_address_t *addr;
3117 index_t index = va_arg (*args, index_t);
3118 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3119 s = format (s, "SR: Segment List index:[%d]", index);
3120 s = format (s, "\n\tSegments:");
3122 sl = pool_elt_at_index (sm->sid_lists, index);
3124 s = format (s, "< ");
3125 vec_foreach (addr, sl->segments)
3127 s = format (s, "%U, ", format_ip6_address, addr);
3129 s = format (s, "\b\b > - ");
3130 s = format (s, "Weight: %u", sl->weight);
3135 const static dpo_vft_t sr_policy_rewrite_vft = {
3136 .dv_lock = sr_dpo_lock,
3137 .dv_unlock = sr_dpo_unlock,
3138 .dv_format = format_sr_segment_list_dpo,
3141 const static char *const sr_pr_encaps_ip6_nodes[] = {
3142 "sr-pl-rewrite-encaps",
3146 const static char *const sr_pr_encaps_ip4_nodes[] = {
3147 "sr-pl-rewrite-encaps-v4",
3151 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3152 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3153 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3156 const static char *const sr_pr_insert_ip6_nodes[] = {
3157 "sr-pl-rewrite-insert",
3161 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3162 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3165 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3166 "sr-pl-rewrite-b-insert",
3170 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3171 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3174 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3175 "sr-pl-rewrite-b-encaps",
3179 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3180 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3183 /********************* SR Policy Rewrite initialization ***********************/
3185 * @brief SR Policy Rewrite initialization
3188 sr_policy_rewrite_init (vlib_main_t * vm)
3190 ip6_sr_main_t *sm = &sr_main;
3192 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3193 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3194 sizeof (ip6_address_t));
3196 /* Init SR VPO DPOs type */
3197 sr_pr_encaps_dpo_type =
3198 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3200 sr_pr_insert_dpo_type =
3201 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3203 sr_pr_bsid_encaps_dpo_type =
3204 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3206 sr_pr_bsid_insert_dpo_type =
3207 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3209 /* Register the L2 encaps node used in HW redirect */
3210 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3212 sm->fib_table_ip6 = (u32) ~ 0;
3213 sm->fib_table_ip4 = (u32) ~ 0;
3218 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3222 * fd.io coding-style-patch-verification: ON
3225 * eval: (c-set-style "gnu")