2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
116 sr_set_source (ip6_address_t * address)
118 clib_memcpy (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
121 static clib_error_t *
122 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
123 vlib_cli_command_t * cmd)
125 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
128 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
131 return clib_error_return (0, "No address specified");
133 return clib_error_return (0, "No address specified");
137 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
138 .path = "set sr encaps source",
139 .short_help = "set sr encaps source addr <ip6_addr>",
140 .function = set_sr_src_command_fn,
144 /*********************** SR rewrite string computation ************************/
146 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
148 * @param sl is a vector of IPv6 addresses composing the Segment List
150 * @return precomputed rewrite string for encapsulation
153 compute_rewrite_encaps (ip6_address_t * sl)
156 ip6_sr_header_t *srh;
157 ip6_address_t *addrp, *this_address;
158 u32 header_length = 0;
162 header_length += IPv6_DEFAULT_HEADER_LENGTH;
163 if (vec_len (sl) > 1)
165 header_length += sizeof (ip6_sr_header_t);
166 header_length += vec_len (sl) * sizeof (ip6_address_t);
169 vec_validate (rs, header_length - 1);
171 iph = (ip6_header_t *) rs;
172 iph->ip_version_traffic_class_and_flow_label =
173 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
174 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
175 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
176 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
177 iph->protocol = IP_PROTOCOL_IPV6;
178 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
180 if (vec_len (sl) > 1)
182 srh = (ip6_sr_header_t *) (iph + 1);
183 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
184 srh->protocol = IP_PROTOCOL_IPV6;
185 srh->type = ROUTING_HEADER_TYPE_SR;
186 srh->segments_left = vec_len (sl) - 1;
187 srh->first_segment = vec_len (sl) - 1;
188 srh->length = ((sizeof (ip6_sr_header_t) +
189 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
191 srh->reserved = 0x00;
192 addrp = srh->segments + vec_len (sl) - 1;
193 vec_foreach (this_address, sl)
195 clib_memcpy (addrp->as_u8, this_address->as_u8,
196 sizeof (ip6_address_t));
200 iph->dst_address.as_u64[0] = sl->as_u64[0];
201 iph->dst_address.as_u64[1] = sl->as_u64[1];
206 * @brief SR rewrite string computation for SRH insertion (inline)
208 * @param sl is a vector of IPv6 addresses composing the Segment List
210 * @return precomputed rewrite string for SRH insertion
213 compute_rewrite_insert (ip6_address_t * sl)
215 ip6_sr_header_t *srh;
216 ip6_address_t *addrp, *this_address;
217 u32 header_length = 0;
221 header_length += sizeof (ip6_sr_header_t);
222 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
224 vec_validate (rs, header_length - 1);
226 srh = (ip6_sr_header_t *) rs;
227 srh->type = ROUTING_HEADER_TYPE_SR;
228 srh->segments_left = vec_len (sl);
229 srh->first_segment = vec_len (sl);
230 srh->length = ((sizeof (ip6_sr_header_t) +
231 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
233 srh->reserved = 0x0000;
234 addrp = srh->segments + vec_len (sl);
235 vec_foreach (this_address, sl)
237 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
244 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
246 * @param sl is a vector of IPv6 addresses composing the Segment List
248 * @return precomputed rewrite string for SRH insertion with BSID
251 compute_rewrite_bsid (ip6_address_t * sl)
253 ip6_sr_header_t *srh;
254 ip6_address_t *addrp, *this_address;
255 u32 header_length = 0;
259 header_length += sizeof (ip6_sr_header_t);
260 header_length += vec_len (sl) * sizeof (ip6_address_t);
262 vec_validate (rs, header_length - 1);
264 srh = (ip6_sr_header_t *) rs;
265 srh->type = ROUTING_HEADER_TYPE_SR;
266 srh->segments_left = vec_len (sl) - 1;
267 srh->first_segment = vec_len (sl) - 1;
268 srh->length = ((sizeof (ip6_sr_header_t) +
269 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
271 srh->reserved = 0x0000;
272 addrp = srh->segments + vec_len (sl) - 1;
273 vec_foreach (this_address, sl)
275 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
281 /*************************** SR LB helper functions **************************/
283 * @brief Creates a Segment List and adds it to an SR policy
285 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
286 * not necessarily unique. Hence there might be two Segment List within the
287 * same SR Policy with exactly the same segments and same weight.
289 * @param sr_policy is the SR policy where the SL will be added
290 * @param sl is a vector of IPv6 addresses composing the Segment List
291 * @param weight is the weight of the SegmentList (for load-balancing purposes)
292 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
294 * @return pointer to the just created segment list
296 static inline ip6_sr_sl_t *
297 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
300 ip6_sr_main_t *sm = &sr_main;
301 ip6_sr_sl_t *segment_list;
303 pool_get (sm->sid_lists, segment_list);
304 memset (segment_list, 0, sizeof (*segment_list));
306 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
308 /* Fill in segment list */
309 segment_list->weight =
310 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
311 segment_list->segments = vec_dup (sl);
315 segment_list->rewrite = compute_rewrite_encaps (sl);
316 segment_list->rewrite_bsid = segment_list->rewrite;
320 segment_list->rewrite = compute_rewrite_insert (sl);
321 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
325 dpo_reset (&segment_list->bsid_dpo);
326 dpo_reset (&segment_list->ip6_dpo);
327 dpo_reset (&segment_list->ip4_dpo);
331 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
332 segment_list - sm->sid_lists);
333 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
334 segment_list - sm->sid_lists);
335 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
336 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
341 segment_list - sm->sid_lists);
342 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
343 DPO_PROTO_IP6, segment_list - sm->sid_lists);
350 * @brief Updates the Load Balancer after an SR Policy change
352 * @param sr_policy is the modified SR Policy
355 update_lb (ip6_sr_policy_t * sr_policy)
357 flow_hash_config_t fhc;
359 ip6_sr_sl_t *segment_list;
360 ip6_sr_main_t *sm = &sr_main;
361 load_balance_path_t path;
362 path.path_index = FIB_NODE_INDEX_INVALID;
363 load_balance_path_t *ip4_path_vector = 0;
364 load_balance_path_t *ip6_path_vector = 0;
365 load_balance_path_t *b_path_vector = 0;
367 /* In case LB does not exist, create it */
368 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
371 .fp_proto = FIB_PROTOCOL_IP6,
374 .ip6 = sr_policy->bsid,
378 /* Add FIB entry for BSID */
379 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
382 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
383 load_balance_create (0, DPO_PROTO_IP6, fhc));
385 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
386 load_balance_create (0, DPO_PROTO_IP6, fhc));
388 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
389 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
390 sr_policy->fib_table),
392 FIB_ENTRY_FLAG_EXCLUSIVE,
393 &sr_policy->bsid_dpo);
395 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
398 FIB_ENTRY_FLAG_EXCLUSIVE,
399 &sr_policy->ip6_dpo);
401 if (sr_policy->is_encap)
403 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
404 load_balance_create (0, DPO_PROTO_IP4, fhc));
406 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
409 FIB_ENTRY_FLAG_EXCLUSIVE,
410 &sr_policy->ip4_dpo);
415 /* Create the LB path vector */
416 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
417 vec_foreach (sl_index, sr_policy->segments_lists)
419 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
420 path.path_dpo = segment_list->bsid_dpo;
421 path.path_weight = segment_list->weight;
422 vec_add1 (b_path_vector, path);
423 path.path_dpo = segment_list->ip6_dpo;
424 vec_add1 (ip6_path_vector, path);
425 if (sr_policy->is_encap)
427 path.path_dpo = segment_list->ip4_dpo;
428 vec_add1 (ip4_path_vector, path);
432 /* Update LB multipath */
433 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
434 LOAD_BALANCE_FLAG_NONE);
435 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
436 LOAD_BALANCE_FLAG_NONE);
437 if (sr_policy->is_encap)
438 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
439 LOAD_BALANCE_FLAG_NONE);
442 vec_free (b_path_vector);
443 vec_free (ip6_path_vector);
444 vec_free (ip4_path_vector);
449 * @brief Updates the Replicate DPO after an SR Policy change
451 * @param sr_policy is the modified SR Policy (type spray)
454 update_replicate (ip6_sr_policy_t * sr_policy)
457 ip6_sr_sl_t *segment_list;
458 ip6_sr_main_t *sm = &sr_main;
459 load_balance_path_t path;
460 path.path_index = FIB_NODE_INDEX_INVALID;
461 load_balance_path_t *b_path_vector = 0;
462 load_balance_path_t *ip6_path_vector = 0;
463 load_balance_path_t *ip4_path_vector = 0;
465 /* In case LB does not exist, create it */
466 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
468 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
469 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
471 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
472 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
474 /* Update FIB entry's DPO to point to SR without LB */
476 .fp_proto = FIB_PROTOCOL_IP6,
479 .ip6 = sr_policy->bsid,
482 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
483 sr_policy->fib_table),
485 FIB_ENTRY_FLAG_EXCLUSIVE,
486 &sr_policy->bsid_dpo);
488 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
491 FIB_ENTRY_FLAG_EXCLUSIVE,
492 &sr_policy->ip6_dpo);
494 if (sr_policy->is_encap)
496 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
497 replicate_create (0, DPO_PROTO_IP4));
499 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
502 FIB_ENTRY_FLAG_EXCLUSIVE,
503 &sr_policy->ip4_dpo);
508 /* Create the replicate path vector */
509 path.path_weight = 1;
510 vec_foreach (sl_index, sr_policy->segments_lists)
512 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
513 path.path_dpo = segment_list->bsid_dpo;
514 vec_add1 (b_path_vector, path);
515 path.path_dpo = segment_list->ip6_dpo;
516 vec_add1 (ip6_path_vector, path);
517 if (sr_policy->is_encap)
519 path.path_dpo = segment_list->ip4_dpo;
520 vec_add1 (ip4_path_vector, path);
524 /* Update replicate multipath */
525 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
526 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
527 if (sr_policy->is_encap)
528 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
531 /******************************* SR rewrite API *******************************/
532 /* Three functions for handling sr policies:
536 * All of them are API. CLI function on sr_policy_command_fn */
539 * @brief Create a new SR policy
541 * @param bsid is the bindingSID of the SR Policy
542 * @param segments is a vector of IPv6 address composing the segment list
543 * @param weight is the weight of the sid list. optional.
544 * @param behavior is the behavior of the SR policy. (default//spray)
545 * @param fib_table is the VRF where to install the FIB entry for the BSID
546 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
548 * @return 0 if correct, else error
551 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
552 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
554 ip6_sr_main_t *sm = &sr_main;
555 ip6_sr_policy_t *sr_policy = 0;
558 /* Search for existing keys (BSID) */
559 p = mhash_get (&sm->sr_policies_index_hash, bsid);
562 /* Add SR policy that already exists; complain */
566 /* Search collision in FIB entries */
567 /* Explanation: It might be possible that some other entity has already
568 * created a route for the BSID. This in theory is impossible, but in
569 * practise we could see it. Assert it and scream if needed */
571 .fp_proto = FIB_PROTOCOL_IP6,
578 /* Lookup the FIB index associated to the table selected */
579 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
580 (fib_table != (u32) ~ 0 ? fib_table : 0));
584 /* Lookup whether there exists an entry for the BSID */
585 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
586 if (FIB_NODE_INDEX_INVALID != fei)
587 return -12; //There is an entry for such lookup
589 /* Add an SR policy object */
590 pool_get (sm->sr_policies, sr_policy);
591 memset (sr_policy, 0, sizeof (*sr_policy));
592 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
593 sr_policy->type = behavior;
594 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
595 sr_policy->is_encap = is_encap;
598 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
601 /* Create a segment list and add the index to the SR policy */
602 create_sl (sr_policy, segments, weight, is_encap);
604 /* If FIB doesnt exist, create them */
605 if (sm->fib_table_ip6 == (u32) ~ 0)
607 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
609 "SRv6 steering of IP6 prefixes through BSIDs");
610 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
612 "SRv6 steering of IP4 prefixes through BSIDs");
615 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
616 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
617 update_lb (sr_policy);
618 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
619 update_replicate (sr_policy);
624 * @brief Delete a SR policy
626 * @param bsid is the bindingSID of the SR Policy
627 * @param index is the index of the SR policy
629 * @return 0 if correct, else error
632 sr_policy_del (ip6_address_t * bsid, u32 index)
634 ip6_sr_main_t *sm = &sr_main;
635 ip6_sr_policy_t *sr_policy = 0;
636 ip6_sr_sl_t *segment_list;
642 p = mhash_get (&sm->sr_policies_index_hash, bsid);
644 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
650 sr_policy = pool_elt_at_index (sm->sr_policies, index);
655 /* Remove BindingSID FIB entry */
657 .fp_proto = FIB_PROTOCOL_IP6,
660 .ip6 = sr_policy->bsid,
665 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
666 sr_policy->fib_table),
667 &pfx, FIB_SOURCE_SR);
669 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
671 if (sr_policy->is_encap)
672 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
674 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
676 dpo_reset (&sr_policy->bsid_dpo);
677 dpo_reset (&sr_policy->ip4_dpo);
678 dpo_reset (&sr_policy->ip6_dpo);
681 /* Clean SID Lists */
682 vec_foreach (sl_index, sr_policy->segments_lists)
684 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
685 vec_free (segment_list->segments);
686 vec_free (segment_list->rewrite);
687 if (!sr_policy->is_encap)
688 vec_free (segment_list->rewrite_bsid);
689 pool_put_index (sm->sid_lists, *sl_index);
692 /* Remove SR policy entry */
693 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
694 pool_put (sm->sr_policies, sr_policy);
696 /* If FIB empty unlock it */
697 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
699 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
700 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
701 sm->fib_table_ip6 = (u32) ~ 0;
702 sm->fib_table_ip4 = (u32) ~ 0;
709 * @brief Modify an existing SR policy
711 * The possible modifications are adding a new Segment List, modifying an
712 * existing Segment List (modify the weight only) and delete a given
713 * Segment List from the SR Policy.
715 * @param bsid is the bindingSID of the SR Policy
716 * @param index is the index of the SR policy
717 * @param fib_table is the VRF where to install the FIB entry for the BSID
718 * @param operation is the operation to perform (among the top ones)
719 * @param segments is a vector of IPv6 address composing the segment list
720 * @param sl_index is the index of the Segment List to modify/delete
721 * @param weight is the weight of the sid list. optional.
722 * @param is_encap Mode. Encapsulation or SRH insertion.
724 * @return 0 if correct, else error
727 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
728 u8 operation, ip6_address_t * segments, u32 sl_index,
731 ip6_sr_main_t *sm = &sr_main;
732 ip6_sr_policy_t *sr_policy = 0;
733 ip6_sr_sl_t *segment_list;
734 u32 *sl_index_iterate;
739 p = mhash_get (&sm->sr_policies_index_hash, bsid);
741 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
747 sr_policy = pool_elt_at_index (sm->sr_policies, index);
752 if (operation == 1) /* Add SR List to an existing SR policy */
754 /* Create the new SL */
756 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
758 /* Create a new LB DPO */
759 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
760 update_lb (sr_policy);
761 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
762 update_replicate (sr_policy);
764 else if (operation == 2) /* Delete SR List from an existing SR policy */
766 /* Check that currently there are more than one SID list */
767 if (vec_len (sr_policy->segments_lists) == 1)
770 /* Check that the SR list does exist and is assigned to the sr policy */
771 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
772 if (*sl_index_iterate == sl_index)
775 if (*sl_index_iterate != sl_index)
778 /* Remove the lucky SR list that is being kicked out */
779 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
780 vec_free (segment_list->segments);
781 vec_free (segment_list->rewrite);
782 if (!sr_policy->is_encap)
783 vec_free (segment_list->rewrite_bsid);
784 pool_put_index (sm->sid_lists, sl_index);
785 vec_del1 (sr_policy->segments_lists,
786 sl_index_iterate - sr_policy->segments_lists);
788 /* Create a new LB DPO */
789 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
790 update_lb (sr_policy);
791 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
792 update_replicate (sr_policy);
794 else if (operation == 3) /* Modify the weight of an existing SR List */
796 /* Find the corresponding SL */
797 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
798 if (*sl_index_iterate == sl_index)
801 if (*sl_index_iterate != sl_index)
804 /* Change the weight */
805 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
806 segment_list->weight = weight;
809 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
810 update_lb (sr_policy);
812 else /* Incorrect op. */
819 * @brief CLI for 'sr policies' command family
821 static clib_error_t *
822 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
823 vlib_cli_command_t * cmd)
826 char is_del = 0, is_add = 0, is_mod = 0;
828 ip6_address_t bsid, next_address;
829 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
830 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
831 ip6_address_t *segments = 0, *this_seg;
836 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
838 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
840 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
842 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
845 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
847 else if (!is_add && !policy_set
848 && unformat (input, "index %d", &sr_policy_index))
850 else if (unformat (input, "weight %d", &weight));
852 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
854 vec_add2 (segments, this_seg, 1);
855 clib_memcpy (this_seg->as_u8, next_address.as_u8,
858 else if (unformat (input, "add sl"))
860 else if (unformat (input, "del sl index %d", &sl_index))
862 else if (unformat (input, "mod sl index %d", &sl_index))
864 else if (fib_table == (u32) ~ 0
865 && unformat (input, "fib-table %d", &fib_table));
866 else if (unformat (input, "encap"))
868 else if (unformat (input, "insert"))
870 else if (unformat (input, "spray"))
876 if (!is_add && !is_mod && !is_del)
877 return clib_error_return (0, "Incorrect CLI");
880 return clib_error_return (0, "No SR policy BSID or index specified");
884 if (vec_len (segments) == 0)
885 return clib_error_return (0, "No Segment List specified");
886 rv = sr_policy_add (&bsid, segments, weight,
887 (is_spray ? SR_POLICY_TYPE_SPRAY :
888 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
892 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
897 return clib_error_return (0, "No SL modification specified");
898 if (operation != 1 && sl_index == (u32) ~ 0)
899 return clib_error_return (0, "No Segment List index specified");
900 if (operation == 1 && vec_len (segments) == 0)
901 return clib_error_return (0, "No Segment List specified");
902 if (operation == 3 && weight == (u32) ~ 0)
903 return clib_error_return (0, "No new weight for the SL specified");
904 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
905 sr_policy_index, fib_table, operation, segments,
917 return clib_error_return (0,
918 "There is already a FIB entry for the BindingSID address.\n"
919 "The SR policy could not be created.");
921 return clib_error_return (0, "The specified FIB table does not exist.");
923 return clib_error_return (0,
924 "The selected SR policy only contains ONE segment list. "
925 "Please remove the SR policy instead");
927 return clib_error_return (0,
928 "Could not delete the segment list. "
929 "It is not associated with that SR policy.");
931 return clib_error_return (0,
932 "Could not modify the segment list. "
933 "The given SL is not associated with such SR policy.");
935 return clib_error_return (0, "BUG: sr policy returns %d", rv);
941 VLIB_CLI_COMMAND (sr_policy_command, static) = {
943 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
944 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
946 "Manipulation of SR policies.\n"
947 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
948 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
949 "Segment Routing policies might be of type encapsulation or srh insertion\n"
950 "Each SR policy will be associated with a unique BindingSID.\n"
951 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
952 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
953 "The add command will create a SR policy with its first segment list (sl)\n"
954 "The mod command allows you to add, remove, or modify the existing segment lists\n"
955 "within an SR policy.\n"
956 "The del command allows you to delete a SR policy along with all its associated\n"
958 .function = sr_policy_command_fn,
963 * @brief CLI to display onscreen all the SR policies
965 static clib_error_t *
966 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
967 vlib_cli_command_t * cmd)
969 ip6_sr_main_t *sm = &sr_main;
971 ip6_sr_sl_t *segment_list = 0;
972 ip6_sr_policy_t *sr_policy = 0;
973 ip6_sr_policy_t **vec_policies = 0;
978 vlib_cli_output (vm, "SR policies:");
981 pool_foreach (sr_policy, sm->sr_policies,
982 {vec_add1 (vec_policies, sr_policy); } );
985 vec_foreach_index (i, vec_policies)
987 sr_policy = vec_policies[i];
988 vlib_cli_output (vm, "[%u].-\tBSID: %U",
989 (u32) (sr_policy - sm->sr_policies),
990 format_ip6_address, &sr_policy->bsid);
991 vlib_cli_output (vm, "\tBehavior: %s",
992 (sr_policy->is_encap ? "Encapsulation" :
994 vlib_cli_output (vm, "\tType: %s",
996 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
997 vlib_cli_output (vm, "\tFIB table: %u",
998 (sr_policy->fib_table !=
999 (u32) ~ 0 ? sr_policy->fib_table : 0));
1000 vlib_cli_output (vm, "\tSegment Lists:");
1001 vec_foreach (sl_index, sr_policy->segments_lists)
1004 s = format (s, "\t[%u].- ", *sl_index);
1005 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1006 s = format (s, "< ");
1007 vec_foreach (addr, segment_list->segments)
1009 s = format (s, "%U, ", format_ip6_address, addr);
1011 s = format (s, "\b\b > ");
1012 s = format (s, "weight: %u", segment_list->weight);
1013 vlib_cli_output (vm, " %s", s);
1015 vlib_cli_output (vm, "-----------");
1021 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1022 .path = "show sr policies",
1023 .short_help = "show sr policies",
1024 .function = show_sr_policies_command_fn,
1028 /*************************** SR rewrite graph node ****************************/
1030 * @brief Trace for the SR Policy Rewrite graph node
1033 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1036 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1037 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1038 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1041 (s, "SR-policy-rewrite: src %U dst %U",
1042 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1048 * @brief IPv6 encapsulation processing as per RFC2473
1050 static_always_inline void
1051 encaps_processing_v6 (vlib_node_runtime_t * node,
1053 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1057 ip0_encap->hop_limit -= 1;
1059 ip0->payload_length + sizeof (ip6_header_t) +
1060 clib_net_to_host_u16 (ip0_encap->payload_length);
1061 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1062 ip0->ip_version_traffic_class_and_flow_label =
1063 ip0_encap->ip_version_traffic_class_and_flow_label;
1067 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1070 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1071 vlib_frame_t * from_frame)
1073 ip6_sr_main_t *sm = &sr_main;
1074 u32 n_left_from, next_index, *from, *to_next;
1076 from = vlib_frame_vector_args (from_frame);
1077 n_left_from = from_frame->n_vectors;
1079 next_index = node->cached_next_index;
1081 int encap_pkts = 0, bsid_pkts = 0;
1083 while (n_left_from > 0)
1087 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1090 while (n_left_from >= 8 && n_left_to_next >= 4)
1092 u32 bi0, bi1, bi2, bi3;
1093 vlib_buffer_t *b0, *b1, *b2, *b3;
1094 u32 next0, next1, next2, next3;
1095 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1096 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1097 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1098 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1100 /* Prefetch next iteration. */
1102 vlib_buffer_t *p4, *p5, *p6, *p7;
1104 p4 = vlib_get_buffer (vm, from[4]);
1105 p5 = vlib_get_buffer (vm, from[5]);
1106 p6 = vlib_get_buffer (vm, from[6]);
1107 p7 = vlib_get_buffer (vm, from[7]);
1109 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1110 vlib_prefetch_buffer_header (p4, LOAD);
1111 vlib_prefetch_buffer_header (p5, LOAD);
1112 vlib_prefetch_buffer_header (p6, LOAD);
1113 vlib_prefetch_buffer_header (p7, LOAD);
1115 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1116 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1117 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1118 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1121 to_next[0] = bi0 = from[0];
1122 to_next[1] = bi1 = from[1];
1123 to_next[2] = bi2 = from[2];
1124 to_next[3] = bi3 = from[3];
1128 n_left_to_next -= 4;
1130 b0 = vlib_get_buffer (vm, bi0);
1131 b1 = vlib_get_buffer (vm, bi1);
1132 b2 = vlib_get_buffer (vm, bi2);
1133 b3 = vlib_get_buffer (vm, bi3);
1136 pool_elt_at_index (sm->sid_lists,
1137 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1139 pool_elt_at_index (sm->sid_lists,
1140 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1142 pool_elt_at_index (sm->sid_lists,
1143 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1145 pool_elt_at_index (sm->sid_lists,
1146 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1148 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1149 vec_len (sl0->rewrite));
1150 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1151 vec_len (sl1->rewrite));
1152 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1153 vec_len (sl2->rewrite));
1154 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1155 vec_len (sl3->rewrite));
1157 ip0_encap = vlib_buffer_get_current (b0);
1158 ip1_encap = vlib_buffer_get_current (b1);
1159 ip2_encap = vlib_buffer_get_current (b2);
1160 ip3_encap = vlib_buffer_get_current (b3);
1162 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1163 sl0->rewrite, vec_len (sl0->rewrite));
1164 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1165 sl1->rewrite, vec_len (sl1->rewrite));
1166 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1167 sl2->rewrite, vec_len (sl2->rewrite));
1168 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1169 sl3->rewrite, vec_len (sl3->rewrite));
1171 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1172 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1173 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1174 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1176 ip0 = vlib_buffer_get_current (b0);
1177 ip1 = vlib_buffer_get_current (b1);
1178 ip2 = vlib_buffer_get_current (b2);
1179 ip3 = vlib_buffer_get_current (b3);
1181 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1182 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1183 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1184 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1186 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1188 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1190 sr_policy_rewrite_trace_t *tr =
1191 vlib_add_trace (vm, node, b0, sizeof (*tr));
1192 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1193 sizeof (tr->src.as_u8));
1194 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1195 sizeof (tr->dst.as_u8));
1198 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1200 sr_policy_rewrite_trace_t *tr =
1201 vlib_add_trace (vm, node, b1, sizeof (*tr));
1202 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1203 sizeof (tr->src.as_u8));
1204 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1205 sizeof (tr->dst.as_u8));
1208 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1210 sr_policy_rewrite_trace_t *tr =
1211 vlib_add_trace (vm, node, b2, sizeof (*tr));
1212 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1213 sizeof (tr->src.as_u8));
1214 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1215 sizeof (tr->dst.as_u8));
1218 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1220 sr_policy_rewrite_trace_t *tr =
1221 vlib_add_trace (vm, node, b3, sizeof (*tr));
1222 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1223 sizeof (tr->src.as_u8));
1224 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1225 sizeof (tr->dst.as_u8));
1230 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1231 n_left_to_next, bi0, bi1, bi2, bi3,
1232 next0, next1, next2, next3);
1235 /* Single loop for potentially the last three packets */
1236 while (n_left_from > 0 && n_left_to_next > 0)
1240 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1242 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1249 n_left_to_next -= 1;
1250 b0 = vlib_get_buffer (vm, bi0);
1253 pool_elt_at_index (sm->sid_lists,
1254 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1255 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1256 vec_len (sl0->rewrite));
1258 ip0_encap = vlib_buffer_get_current (b0);
1260 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1261 sl0->rewrite, vec_len (sl0->rewrite));
1262 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1264 ip0 = vlib_buffer_get_current (b0);
1266 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1268 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1269 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1271 sr_policy_rewrite_trace_t *tr =
1272 vlib_add_trace (vm, node, b0, sizeof (*tr));
1273 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1274 sizeof (tr->src.as_u8));
1275 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1276 sizeof (tr->dst.as_u8));
1280 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1281 n_left_to_next, bi0, next0);
1284 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1287 /* Update counters */
1288 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1289 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1291 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1292 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1295 return from_frame->n_vectors;
1299 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1300 .function = sr_policy_rewrite_encaps,
1301 .name = "sr-pl-rewrite-encaps",
1302 .vector_size = sizeof (u32),
1303 .format_trace = format_sr_policy_rewrite_trace,
1304 .type = VLIB_NODE_TYPE_INTERNAL,
1305 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1306 .error_strings = sr_policy_rewrite_error_strings,
1307 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1309 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1310 foreach_sr_policy_rewrite_next
1317 * @brief IPv4 encapsulation processing as per RFC2473
1319 static_always_inline void
1320 encaps_processing_v4 (vlib_node_runtime_t * node,
1322 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1325 ip6_sr_header_t *sr0;
1329 /* Inner IPv4: Decrement TTL & update checksum */
1330 ip0_encap->ttl -= 1;
1331 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1332 checksum0 += checksum0 >= 0xffff;
1333 ip0_encap->checksum = checksum0;
1335 /* Outer IPv6: Update length, FL, proto */
1336 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1337 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1338 ip0->ip_version_traffic_class_and_flow_label =
1339 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1340 ((ip0_encap->tos & 0xFF) << 20));
1341 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1343 sr0 = (void *) (ip0 + 1);
1344 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1347 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1351 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1354 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1355 vlib_frame_t * from_frame)
1357 ip6_sr_main_t *sm = &sr_main;
1358 u32 n_left_from, next_index, *from, *to_next;
1360 from = vlib_frame_vector_args (from_frame);
1361 n_left_from = from_frame->n_vectors;
1363 next_index = node->cached_next_index;
1365 int encap_pkts = 0, bsid_pkts = 0;
1367 while (n_left_from > 0)
1371 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1374 while (n_left_from >= 8 && n_left_to_next >= 4)
1376 u32 bi0, bi1, bi2, bi3;
1377 vlib_buffer_t *b0, *b1, *b2, *b3;
1378 u32 next0, next1, next2, next3;
1379 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1380 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1381 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1382 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1384 /* Prefetch next iteration. */
1386 vlib_buffer_t *p4, *p5, *p6, *p7;
1388 p4 = vlib_get_buffer (vm, from[4]);
1389 p5 = vlib_get_buffer (vm, from[5]);
1390 p6 = vlib_get_buffer (vm, from[6]);
1391 p7 = vlib_get_buffer (vm, from[7]);
1393 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1394 vlib_prefetch_buffer_header (p4, LOAD);
1395 vlib_prefetch_buffer_header (p5, LOAD);
1396 vlib_prefetch_buffer_header (p6, LOAD);
1397 vlib_prefetch_buffer_header (p7, LOAD);
1399 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1400 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1401 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1402 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1405 to_next[0] = bi0 = from[0];
1406 to_next[1] = bi1 = from[1];
1407 to_next[2] = bi2 = from[2];
1408 to_next[3] = bi3 = from[3];
1412 n_left_to_next -= 4;
1414 b0 = vlib_get_buffer (vm, bi0);
1415 b1 = vlib_get_buffer (vm, bi1);
1416 b2 = vlib_get_buffer (vm, bi2);
1417 b3 = vlib_get_buffer (vm, bi3);
1420 pool_elt_at_index (sm->sid_lists,
1421 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1423 pool_elt_at_index (sm->sid_lists,
1424 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1426 pool_elt_at_index (sm->sid_lists,
1427 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1429 pool_elt_at_index (sm->sid_lists,
1430 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1431 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1432 vec_len (sl0->rewrite));
1433 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1434 vec_len (sl1->rewrite));
1435 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1436 vec_len (sl2->rewrite));
1437 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1438 vec_len (sl3->rewrite));
1440 ip0_encap = vlib_buffer_get_current (b0);
1441 ip1_encap = vlib_buffer_get_current (b1);
1442 ip2_encap = vlib_buffer_get_current (b2);
1443 ip3_encap = vlib_buffer_get_current (b3);
1445 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1446 sl0->rewrite, vec_len (sl0->rewrite));
1447 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1448 sl1->rewrite, vec_len (sl1->rewrite));
1449 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1450 sl2->rewrite, vec_len (sl2->rewrite));
1451 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1452 sl3->rewrite, vec_len (sl3->rewrite));
1454 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1455 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1456 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1457 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1459 ip0 = vlib_buffer_get_current (b0);
1460 ip1 = vlib_buffer_get_current (b1);
1461 ip2 = vlib_buffer_get_current (b2);
1462 ip3 = vlib_buffer_get_current (b3);
1464 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1465 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1466 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1467 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1469 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1471 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1473 sr_policy_rewrite_trace_t *tr =
1474 vlib_add_trace (vm, node, b0, sizeof (*tr));
1475 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1476 sizeof (tr->src.as_u8));
1477 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1478 sizeof (tr->dst.as_u8));
1481 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1483 sr_policy_rewrite_trace_t *tr =
1484 vlib_add_trace (vm, node, b1, sizeof (*tr));
1485 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1486 sizeof (tr->src.as_u8));
1487 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1488 sizeof (tr->dst.as_u8));
1491 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1493 sr_policy_rewrite_trace_t *tr =
1494 vlib_add_trace (vm, node, b2, sizeof (*tr));
1495 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1496 sizeof (tr->src.as_u8));
1497 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1498 sizeof (tr->dst.as_u8));
1501 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1503 sr_policy_rewrite_trace_t *tr =
1504 vlib_add_trace (vm, node, b3, sizeof (*tr));
1505 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1506 sizeof (tr->src.as_u8));
1507 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1508 sizeof (tr->dst.as_u8));
1513 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1514 n_left_to_next, bi0, bi1, bi2, bi3,
1515 next0, next1, next2, next3);
1518 /* Single loop for potentially the last three packets */
1519 while (n_left_from > 0 && n_left_to_next > 0)
1523 ip6_header_t *ip0 = 0;
1524 ip4_header_t *ip0_encap = 0;
1526 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1533 n_left_to_next -= 1;
1534 b0 = vlib_get_buffer (vm, bi0);
1537 pool_elt_at_index (sm->sid_lists,
1538 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1539 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1540 vec_len (sl0->rewrite));
1542 ip0_encap = vlib_buffer_get_current (b0);
1544 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1545 sl0->rewrite, vec_len (sl0->rewrite));
1546 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1548 ip0 = vlib_buffer_get_current (b0);
1550 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1552 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1553 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1555 sr_policy_rewrite_trace_t *tr =
1556 vlib_add_trace (vm, node, b0, sizeof (*tr));
1557 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1558 sizeof (tr->src.as_u8));
1559 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1560 sizeof (tr->dst.as_u8));
1564 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1565 n_left_to_next, bi0, next0);
1568 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1571 /* Update counters */
1572 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1573 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1575 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1576 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1579 return from_frame->n_vectors;
1583 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1584 .function = sr_policy_rewrite_encaps_v4,
1585 .name = "sr-pl-rewrite-encaps-v4",
1586 .vector_size = sizeof (u32),
1587 .format_trace = format_sr_policy_rewrite_trace,
1588 .type = VLIB_NODE_TYPE_INTERNAL,
1589 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1590 .error_strings = sr_policy_rewrite_error_strings,
1591 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1593 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1594 foreach_sr_policy_rewrite_next
1601 ip_flow_hash (void *data)
1603 ip4_header_t *iph = (ip4_header_t *) data;
1605 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1606 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1608 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1614 return (*((u64 *) m) & 0xffffffffffff);
1618 l2_flow_hash (vlib_buffer_t * b0)
1620 ethernet_header_t *eh;
1622 uword is_ip, eh_size;
1625 eh = vlib_buffer_get_current (b0);
1626 eh_type = clib_net_to_host_u16 (eh->type);
1627 eh_size = ethernet_buffer_header_size (b0);
1629 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1631 /* since we have 2 cache lines, use them */
1633 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1637 b = mac_to_u64 ((u8 *) eh->dst_address);
1638 c = mac_to_u64 ((u8 *) eh->src_address);
1639 hash_mix64 (a, b, c);
1645 * @brief Graph node for applying a SR policy into a L2 frame
1648 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1649 vlib_frame_t * from_frame)
1651 ip6_sr_main_t *sm = &sr_main;
1652 u32 n_left_from, next_index, *from, *to_next;
1654 from = vlib_frame_vector_args (from_frame);
1655 n_left_from = from_frame->n_vectors;
1657 next_index = node->cached_next_index;
1659 int encap_pkts = 0, bsid_pkts = 0;
1661 while (n_left_from > 0)
1665 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1668 while (n_left_from >= 8 && n_left_to_next >= 4)
1670 u32 bi0, bi1, bi2, bi3;
1671 vlib_buffer_t *b0, *b1, *b2, *b3;
1672 u32 next0, next1, next2, next3;
1673 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1674 ethernet_header_t *en0, *en1, *en2, *en3;
1675 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1676 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1677 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1678 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1680 /* Prefetch next iteration. */
1682 vlib_buffer_t *p4, *p5, *p6, *p7;
1684 p4 = vlib_get_buffer (vm, from[4]);
1685 p5 = vlib_get_buffer (vm, from[5]);
1686 p6 = vlib_get_buffer (vm, from[6]);
1687 p7 = vlib_get_buffer (vm, from[7]);
1689 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1690 vlib_prefetch_buffer_header (p4, LOAD);
1691 vlib_prefetch_buffer_header (p5, LOAD);
1692 vlib_prefetch_buffer_header (p6, LOAD);
1693 vlib_prefetch_buffer_header (p7, LOAD);
1695 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1696 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1697 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1698 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1701 to_next[0] = bi0 = from[0];
1702 to_next[1] = bi1 = from[1];
1703 to_next[2] = bi2 = from[2];
1704 to_next[3] = bi3 = from[3];
1708 n_left_to_next -= 4;
1710 b0 = vlib_get_buffer (vm, bi0);
1711 b1 = vlib_get_buffer (vm, bi1);
1712 b2 = vlib_get_buffer (vm, bi2);
1713 b3 = vlib_get_buffer (vm, bi3);
1715 sp0 = pool_elt_at_index (sm->sr_policies,
1716 sm->sw_iface_sr_policies[vnet_buffer
1720 sp1 = pool_elt_at_index (sm->sr_policies,
1721 sm->sw_iface_sr_policies[vnet_buffer
1725 sp2 = pool_elt_at_index (sm->sr_policies,
1726 sm->sw_iface_sr_policies[vnet_buffer
1730 sp3 = pool_elt_at_index (sm->sr_policies,
1731 sm->sw_iface_sr_policies[vnet_buffer
1735 if (vec_len (sp0->segments_lists) == 1)
1736 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1739 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1740 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1741 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1742 (vec_len (sp0->segments_lists) - 1))];
1745 if (vec_len (sp1->segments_lists) == 1)
1746 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1749 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1750 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1751 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1752 (vec_len (sp1->segments_lists) - 1))];
1755 if (vec_len (sp2->segments_lists) == 1)
1756 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1759 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1760 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1761 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1762 (vec_len (sp2->segments_lists) - 1))];
1765 if (vec_len (sp3->segments_lists) == 1)
1766 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1769 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1770 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1771 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1772 (vec_len (sp3->segments_lists) - 1))];
1776 pool_elt_at_index (sm->sid_lists,
1777 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1779 pool_elt_at_index (sm->sid_lists,
1780 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1782 pool_elt_at_index (sm->sid_lists,
1783 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1785 pool_elt_at_index (sm->sid_lists,
1786 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1788 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1789 vec_len (sl0->rewrite));
1790 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1791 vec_len (sl1->rewrite));
1792 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1793 vec_len (sl2->rewrite));
1794 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1795 vec_len (sl3->rewrite));
1797 en0 = vlib_buffer_get_current (b0);
1798 en1 = vlib_buffer_get_current (b1);
1799 en2 = vlib_buffer_get_current (b2);
1800 en3 = vlib_buffer_get_current (b3);
1802 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1803 vec_len (sl0->rewrite));
1804 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1805 vec_len (sl1->rewrite));
1806 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1807 vec_len (sl2->rewrite));
1808 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1809 vec_len (sl3->rewrite));
1811 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1812 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1813 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1814 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1816 ip0 = vlib_buffer_get_current (b0);
1817 ip1 = vlib_buffer_get_current (b1);
1818 ip2 = vlib_buffer_get_current (b2);
1819 ip3 = vlib_buffer_get_current (b3);
1821 ip0->payload_length =
1822 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1823 ip1->payload_length =
1824 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1825 ip2->payload_length =
1826 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1827 ip3->payload_length =
1828 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1830 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1832 sr0 = (void *) (ip0 + 1);
1833 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1836 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1838 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1840 sr1 = (void *) (ip1 + 1);
1841 sr1->protocol = IP_PROTOCOL_IP6_NONXT;
1844 ip1->protocol = IP_PROTOCOL_IP6_NONXT;
1846 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1848 sr2 = (void *) (ip2 + 1);
1849 sr2->protocol = IP_PROTOCOL_IP6_NONXT;
1852 ip2->protocol = IP_PROTOCOL_IP6_NONXT;
1854 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1856 sr3 = (void *) (ip3 + 1);
1857 sr3->protocol = IP_PROTOCOL_IP6_NONXT;
1860 ip3->protocol = IP_PROTOCOL_IP6_NONXT;
1862 /* Which Traffic class and flow label do I set ? */
1863 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1865 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1867 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1869 sr_policy_rewrite_trace_t *tr =
1870 vlib_add_trace (vm, node, b0, sizeof (*tr));
1871 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1872 sizeof (tr->src.as_u8));
1873 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1874 sizeof (tr->dst.as_u8));
1877 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1879 sr_policy_rewrite_trace_t *tr =
1880 vlib_add_trace (vm, node, b1, sizeof (*tr));
1881 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1882 sizeof (tr->src.as_u8));
1883 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1884 sizeof (tr->dst.as_u8));
1887 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1889 sr_policy_rewrite_trace_t *tr =
1890 vlib_add_trace (vm, node, b2, sizeof (*tr));
1891 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1892 sizeof (tr->src.as_u8));
1893 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1894 sizeof (tr->dst.as_u8));
1897 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1899 sr_policy_rewrite_trace_t *tr =
1900 vlib_add_trace (vm, node, b3, sizeof (*tr));
1901 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1902 sizeof (tr->src.as_u8));
1903 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1904 sizeof (tr->dst.as_u8));
1909 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1910 n_left_to_next, bi0, bi1, bi2, bi3,
1911 next0, next1, next2, next3);
1914 /* Single loop for potentially the last three packets */
1915 while (n_left_from > 0 && n_left_to_next > 0)
1919 ip6_header_t *ip0 = 0;
1920 ip6_sr_header_t *sr0;
1921 ethernet_header_t *en0;
1922 ip6_sr_policy_t *sp0;
1924 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1931 n_left_to_next -= 1;
1932 b0 = vlib_get_buffer (vm, bi0);
1934 /* Find the SR policy */
1935 sp0 = pool_elt_at_index (sm->sr_policies,
1936 sm->sw_iface_sr_policies[vnet_buffer
1940 /* In case there is more than one SL, LB among them */
1941 if (vec_len (sp0->segments_lists) == 1)
1942 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1945 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1946 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1947 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1948 (vec_len (sp0->segments_lists) - 1))];
1951 pool_elt_at_index (sm->sid_lists,
1952 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1953 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1954 vec_len (sl0->rewrite));
1956 en0 = vlib_buffer_get_current (b0);
1958 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1959 vec_len (sl0->rewrite));
1961 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1963 ip0 = vlib_buffer_get_current (b0);
1965 ip0->payload_length =
1966 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1968 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1970 sr0 = (void *) (ip0 + 1);
1971 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1974 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1976 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1977 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1979 sr_policy_rewrite_trace_t *tr =
1980 vlib_add_trace (vm, node, b0, sizeof (*tr));
1981 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1982 sizeof (tr->src.as_u8));
1983 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1984 sizeof (tr->dst.as_u8));
1988 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1989 n_left_to_next, bi0, next0);
1992 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1995 /* Update counters */
1996 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1997 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1999 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2000 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2003 return from_frame->n_vectors;
2007 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2008 .function = sr_policy_rewrite_encaps_l2,
2009 .name = "sr-pl-rewrite-encaps-l2",
2010 .vector_size = sizeof (u32),
2011 .format_trace = format_sr_policy_rewrite_trace,
2012 .type = VLIB_NODE_TYPE_INTERNAL,
2013 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2014 .error_strings = sr_policy_rewrite_error_strings,
2015 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2017 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2018 foreach_sr_policy_rewrite_next
2025 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2028 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2029 vlib_frame_t * from_frame)
2031 ip6_sr_main_t *sm = &sr_main;
2032 u32 n_left_from, next_index, *from, *to_next;
2034 from = vlib_frame_vector_args (from_frame);
2035 n_left_from = from_frame->n_vectors;
2037 next_index = node->cached_next_index;
2039 int insert_pkts = 0, bsid_pkts = 0;
2041 while (n_left_from > 0)
2045 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2048 while (n_left_from >= 8 && n_left_to_next >= 4)
2050 u32 bi0, bi1, bi2, bi3;
2051 vlib_buffer_t *b0, *b1, *b2, *b3;
2052 u32 next0, next1, next2, next3;
2053 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2054 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2055 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2056 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2057 u16 new_l0, new_l1, new_l2, new_l3;
2059 /* Prefetch next iteration. */
2061 vlib_buffer_t *p4, *p5, *p6, *p7;
2063 p4 = vlib_get_buffer (vm, from[4]);
2064 p5 = vlib_get_buffer (vm, from[5]);
2065 p6 = vlib_get_buffer (vm, from[6]);
2066 p7 = vlib_get_buffer (vm, from[7]);
2068 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2069 vlib_prefetch_buffer_header (p4, LOAD);
2070 vlib_prefetch_buffer_header (p5, LOAD);
2071 vlib_prefetch_buffer_header (p6, LOAD);
2072 vlib_prefetch_buffer_header (p7, LOAD);
2074 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2075 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2076 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2077 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2080 to_next[0] = bi0 = from[0];
2081 to_next[1] = bi1 = from[1];
2082 to_next[2] = bi2 = from[2];
2083 to_next[3] = bi3 = from[3];
2087 n_left_to_next -= 4;
2089 b0 = vlib_get_buffer (vm, bi0);
2090 b1 = vlib_get_buffer (vm, bi1);
2091 b2 = vlib_get_buffer (vm, bi2);
2092 b3 = vlib_get_buffer (vm, bi3);
2095 pool_elt_at_index (sm->sid_lists,
2096 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2098 pool_elt_at_index (sm->sid_lists,
2099 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2101 pool_elt_at_index (sm->sid_lists,
2102 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2104 pool_elt_at_index (sm->sid_lists,
2105 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2106 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2107 vec_len (sl0->rewrite));
2108 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2109 vec_len (sl1->rewrite));
2110 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2111 vec_len (sl2->rewrite));
2112 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2113 vec_len (sl3->rewrite));
2115 ip0 = vlib_buffer_get_current (b0);
2116 ip1 = vlib_buffer_get_current (b1);
2117 ip2 = vlib_buffer_get_current (b2);
2118 ip3 = vlib_buffer_get_current (b3);
2120 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2122 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2123 ip6_ext_header_len (ip0 + 1));
2125 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2127 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2129 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2130 ip6_ext_header_len (ip1 + 1));
2132 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2134 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2136 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2137 ip6_ext_header_len (ip2 + 1));
2139 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2141 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2143 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2144 ip6_ext_header_len (ip3 + 1));
2146 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2148 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2149 (void *) sr0 - (void *) ip0);
2150 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2151 (void *) sr1 - (void *) ip1);
2152 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2153 (void *) sr2 - (void *) ip2);
2154 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2155 (void *) sr3 - (void *) ip3);
2157 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2158 vec_len (sl0->rewrite));
2159 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2160 vec_len (sl1->rewrite));
2161 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2162 vec_len (sl2->rewrite));
2163 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2164 vec_len (sl3->rewrite));
2166 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2167 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2168 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2169 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2171 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2172 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2173 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2174 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2176 ip0->hop_limit -= 1;
2177 ip1->hop_limit -= 1;
2178 ip2->hop_limit -= 1;
2179 ip3->hop_limit -= 1;
2182 clib_net_to_host_u16 (ip0->payload_length) +
2183 vec_len (sl0->rewrite);
2185 clib_net_to_host_u16 (ip1->payload_length) +
2186 vec_len (sl1->rewrite);
2188 clib_net_to_host_u16 (ip2->payload_length) +
2189 vec_len (sl2->rewrite);
2191 clib_net_to_host_u16 (ip3->payload_length) +
2192 vec_len (sl3->rewrite);
2194 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2195 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2196 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2197 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2199 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2200 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2201 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2202 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2204 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2205 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2206 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2207 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2208 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2209 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2210 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2211 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2213 ip0->dst_address.as_u64[0] =
2214 (sr0->segments + sr0->segments_left)->as_u64[0];
2215 ip0->dst_address.as_u64[1] =
2216 (sr0->segments + sr0->segments_left)->as_u64[1];
2217 ip1->dst_address.as_u64[0] =
2218 (sr1->segments + sr1->segments_left)->as_u64[0];
2219 ip1->dst_address.as_u64[1] =
2220 (sr1->segments + sr1->segments_left)->as_u64[1];
2221 ip2->dst_address.as_u64[0] =
2222 (sr2->segments + sr2->segments_left)->as_u64[0];
2223 ip2->dst_address.as_u64[1] =
2224 (sr2->segments + sr2->segments_left)->as_u64[1];
2225 ip3->dst_address.as_u64[0] =
2226 (sr3->segments + sr3->segments_left)->as_u64[0];
2227 ip3->dst_address.as_u64[1] =
2228 (sr3->segments + sr3->segments_left)->as_u64[1];
2230 ip6_ext_header_t *ip_ext;
2231 if (ip0 + 1 == (void *) sr0)
2233 sr0->protocol = ip0->protocol;
2234 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2238 ip_ext = (void *) (ip0 + 1);
2239 sr0->protocol = ip_ext->next_hdr;
2240 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2243 if (ip1 + 1 == (void *) sr1)
2245 sr1->protocol = ip1->protocol;
2246 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2250 ip_ext = (void *) (ip2 + 1);
2251 sr2->protocol = ip_ext->next_hdr;
2252 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2255 if (ip2 + 1 == (void *) sr2)
2257 sr2->protocol = ip2->protocol;
2258 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2262 ip_ext = (void *) (ip2 + 1);
2263 sr2->protocol = ip_ext->next_hdr;
2264 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2267 if (ip3 + 1 == (void *) sr3)
2269 sr3->protocol = ip3->protocol;
2270 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2274 ip_ext = (void *) (ip3 + 1);
2275 sr3->protocol = ip_ext->next_hdr;
2276 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2281 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2283 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2285 sr_policy_rewrite_trace_t *tr =
2286 vlib_add_trace (vm, node, b0, sizeof (*tr));
2287 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2288 sizeof (tr->src.as_u8));
2289 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2290 sizeof (tr->dst.as_u8));
2293 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2295 sr_policy_rewrite_trace_t *tr =
2296 vlib_add_trace (vm, node, b1, sizeof (*tr));
2297 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2298 sizeof (tr->src.as_u8));
2299 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2300 sizeof (tr->dst.as_u8));
2303 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2305 sr_policy_rewrite_trace_t *tr =
2306 vlib_add_trace (vm, node, b2, sizeof (*tr));
2307 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2308 sizeof (tr->src.as_u8));
2309 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2310 sizeof (tr->dst.as_u8));
2313 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2315 sr_policy_rewrite_trace_t *tr =
2316 vlib_add_trace (vm, node, b3, sizeof (*tr));
2317 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2318 sizeof (tr->src.as_u8));
2319 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2320 sizeof (tr->dst.as_u8));
2324 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2325 n_left_to_next, bi0, bi1, bi2, bi3,
2326 next0, next1, next2, next3);
2329 /* Single loop for potentially the last three packets */
2330 while (n_left_from > 0 && n_left_to_next > 0)
2334 ip6_header_t *ip0 = 0;
2335 ip6_sr_header_t *sr0 = 0;
2337 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2345 n_left_to_next -= 1;
2347 b0 = vlib_get_buffer (vm, bi0);
2349 pool_elt_at_index (sm->sid_lists,
2350 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2351 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2352 vec_len (sl0->rewrite));
2354 ip0 = vlib_buffer_get_current (b0);
2356 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2358 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2359 ip6_ext_header_len (ip0 + 1));
2361 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2363 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2364 (void *) sr0 - (void *) ip0);
2365 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2366 vec_len (sl0->rewrite));
2368 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2370 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2371 ip0->hop_limit -= 1;
2373 clib_net_to_host_u16 (ip0->payload_length) +
2374 vec_len (sl0->rewrite);
2375 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2377 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2378 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2379 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2381 ip0->dst_address.as_u64[0] =
2382 (sr0->segments + sr0->segments_left)->as_u64[0];
2383 ip0->dst_address.as_u64[1] =
2384 (sr0->segments + sr0->segments_left)->as_u64[1];
2386 if (ip0 + 1 == (void *) sr0)
2388 sr0->protocol = ip0->protocol;
2389 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2393 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2394 sr0->protocol = ip_ext->next_hdr;
2395 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2398 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2399 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2401 sr_policy_rewrite_trace_t *tr =
2402 vlib_add_trace (vm, node, b0, sizeof (*tr));
2403 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2404 sizeof (tr->src.as_u8));
2405 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2406 sizeof (tr->dst.as_u8));
2411 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2412 n_left_to_next, bi0, next0);
2415 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2418 /* Update counters */
2419 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2420 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2422 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2423 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2425 return from_frame->n_vectors;
2429 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2430 .function = sr_policy_rewrite_insert,
2431 .name = "sr-pl-rewrite-insert",
2432 .vector_size = sizeof (u32),
2433 .format_trace = format_sr_policy_rewrite_trace,
2434 .type = VLIB_NODE_TYPE_INTERNAL,
2435 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2436 .error_strings = sr_policy_rewrite_error_strings,
2437 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2439 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2440 foreach_sr_policy_rewrite_next
2447 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2450 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2451 vlib_frame_t * from_frame)
2453 ip6_sr_main_t *sm = &sr_main;
2454 u32 n_left_from, next_index, *from, *to_next;
2456 from = vlib_frame_vector_args (from_frame);
2457 n_left_from = from_frame->n_vectors;
2459 next_index = node->cached_next_index;
2461 int insert_pkts = 0, bsid_pkts = 0;
2463 while (n_left_from > 0)
2467 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2470 while (n_left_from >= 8 && n_left_to_next >= 4)
2472 u32 bi0, bi1, bi2, bi3;
2473 vlib_buffer_t *b0, *b1, *b2, *b3;
2474 u32 next0, next1, next2, next3;
2475 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2476 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2477 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2478 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2479 u16 new_l0, new_l1, new_l2, new_l3;
2481 /* Prefetch next iteration. */
2483 vlib_buffer_t *p4, *p5, *p6, *p7;
2485 p4 = vlib_get_buffer (vm, from[4]);
2486 p5 = vlib_get_buffer (vm, from[5]);
2487 p6 = vlib_get_buffer (vm, from[6]);
2488 p7 = vlib_get_buffer (vm, from[7]);
2490 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2491 vlib_prefetch_buffer_header (p4, LOAD);
2492 vlib_prefetch_buffer_header (p5, LOAD);
2493 vlib_prefetch_buffer_header (p6, LOAD);
2494 vlib_prefetch_buffer_header (p7, LOAD);
2496 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2497 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2498 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2499 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2502 to_next[0] = bi0 = from[0];
2503 to_next[1] = bi1 = from[1];
2504 to_next[2] = bi2 = from[2];
2505 to_next[3] = bi3 = from[3];
2509 n_left_to_next -= 4;
2511 b0 = vlib_get_buffer (vm, bi0);
2512 b1 = vlib_get_buffer (vm, bi1);
2513 b2 = vlib_get_buffer (vm, bi2);
2514 b3 = vlib_get_buffer (vm, bi3);
2517 pool_elt_at_index (sm->sid_lists,
2518 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2520 pool_elt_at_index (sm->sid_lists,
2521 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2523 pool_elt_at_index (sm->sid_lists,
2524 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2526 pool_elt_at_index (sm->sid_lists,
2527 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2528 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2529 vec_len (sl0->rewrite_bsid));
2530 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2531 vec_len (sl1->rewrite_bsid));
2532 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2533 vec_len (sl2->rewrite_bsid));
2534 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2535 vec_len (sl3->rewrite_bsid));
2537 ip0 = vlib_buffer_get_current (b0);
2538 ip1 = vlib_buffer_get_current (b1);
2539 ip2 = vlib_buffer_get_current (b2);
2540 ip3 = vlib_buffer_get_current (b3);
2542 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2544 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2545 ip6_ext_header_len (ip0 + 1));
2547 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2549 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2551 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2552 ip6_ext_header_len (ip1 + 1));
2554 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2556 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2558 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2559 ip6_ext_header_len (ip2 + 1));
2561 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2563 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2565 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2566 ip6_ext_header_len (ip3 + 1));
2568 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2570 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2571 (void *) sr0 - (void *) ip0);
2572 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2573 (void *) sr1 - (void *) ip1);
2574 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2575 (void *) sr2 - (void *) ip2);
2576 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2577 (void *) sr3 - (void *) ip3);
2579 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2580 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2581 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2582 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2583 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2584 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2585 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2586 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2588 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2589 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2590 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2591 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2593 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2594 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2595 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2596 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2598 ip0->hop_limit -= 1;
2599 ip1->hop_limit -= 1;
2600 ip2->hop_limit -= 1;
2601 ip3->hop_limit -= 1;
2604 clib_net_to_host_u16 (ip0->payload_length) +
2605 vec_len (sl0->rewrite_bsid);
2607 clib_net_to_host_u16 (ip1->payload_length) +
2608 vec_len (sl1->rewrite_bsid);
2610 clib_net_to_host_u16 (ip2->payload_length) +
2611 vec_len (sl2->rewrite_bsid);
2613 clib_net_to_host_u16 (ip3->payload_length) +
2614 vec_len (sl3->rewrite_bsid);
2616 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2617 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2618 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2619 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2621 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2622 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2623 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2624 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2626 ip0->dst_address.as_u64[0] =
2627 (sr0->segments + sr0->segments_left)->as_u64[0];
2628 ip0->dst_address.as_u64[1] =
2629 (sr0->segments + sr0->segments_left)->as_u64[1];
2630 ip1->dst_address.as_u64[0] =
2631 (sr1->segments + sr1->segments_left)->as_u64[0];
2632 ip1->dst_address.as_u64[1] =
2633 (sr1->segments + sr1->segments_left)->as_u64[1];
2634 ip2->dst_address.as_u64[0] =
2635 (sr2->segments + sr2->segments_left)->as_u64[0];
2636 ip2->dst_address.as_u64[1] =
2637 (sr2->segments + sr2->segments_left)->as_u64[1];
2638 ip3->dst_address.as_u64[0] =
2639 (sr3->segments + sr3->segments_left)->as_u64[0];
2640 ip3->dst_address.as_u64[1] =
2641 (sr3->segments + sr3->segments_left)->as_u64[1];
2643 ip6_ext_header_t *ip_ext;
2644 if (ip0 + 1 == (void *) sr0)
2646 sr0->protocol = ip0->protocol;
2647 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2651 ip_ext = (void *) (ip0 + 1);
2652 sr0->protocol = ip_ext->next_hdr;
2653 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2656 if (ip1 + 1 == (void *) sr1)
2658 sr1->protocol = ip1->protocol;
2659 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2663 ip_ext = (void *) (ip2 + 1);
2664 sr2->protocol = ip_ext->next_hdr;
2665 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2668 if (ip2 + 1 == (void *) sr2)
2670 sr2->protocol = ip2->protocol;
2671 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2675 ip_ext = (void *) (ip2 + 1);
2676 sr2->protocol = ip_ext->next_hdr;
2677 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2680 if (ip3 + 1 == (void *) sr3)
2682 sr3->protocol = ip3->protocol;
2683 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2687 ip_ext = (void *) (ip3 + 1);
2688 sr3->protocol = ip_ext->next_hdr;
2689 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2694 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2696 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2698 sr_policy_rewrite_trace_t *tr =
2699 vlib_add_trace (vm, node, b0, sizeof (*tr));
2700 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2701 sizeof (tr->src.as_u8));
2702 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2703 sizeof (tr->dst.as_u8));
2706 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2708 sr_policy_rewrite_trace_t *tr =
2709 vlib_add_trace (vm, node, b1, sizeof (*tr));
2710 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2711 sizeof (tr->src.as_u8));
2712 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2713 sizeof (tr->dst.as_u8));
2716 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2718 sr_policy_rewrite_trace_t *tr =
2719 vlib_add_trace (vm, node, b2, sizeof (*tr));
2720 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2721 sizeof (tr->src.as_u8));
2722 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2723 sizeof (tr->dst.as_u8));
2726 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2728 sr_policy_rewrite_trace_t *tr =
2729 vlib_add_trace (vm, node, b3, sizeof (*tr));
2730 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2731 sizeof (tr->src.as_u8));
2732 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2733 sizeof (tr->dst.as_u8));
2737 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2738 n_left_to_next, bi0, bi1, bi2, bi3,
2739 next0, next1, next2, next3);
2742 /* Single loop for potentially the last three packets */
2743 while (n_left_from > 0 && n_left_to_next > 0)
2747 ip6_header_t *ip0 = 0;
2748 ip6_sr_header_t *sr0 = 0;
2750 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2758 n_left_to_next -= 1;
2760 b0 = vlib_get_buffer (vm, bi0);
2762 pool_elt_at_index (sm->sid_lists,
2763 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2764 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2765 vec_len (sl0->rewrite_bsid));
2767 ip0 = vlib_buffer_get_current (b0);
2769 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2771 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2772 ip6_ext_header_len (ip0 + 1));
2774 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2776 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2777 (void *) sr0 - (void *) ip0);
2778 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2779 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2781 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2783 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2784 ip0->hop_limit -= 1;
2786 clib_net_to_host_u16 (ip0->payload_length) +
2787 vec_len (sl0->rewrite_bsid);
2788 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2790 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2792 ip0->dst_address.as_u64[0] =
2793 (sr0->segments + sr0->segments_left)->as_u64[0];
2794 ip0->dst_address.as_u64[1] =
2795 (sr0->segments + sr0->segments_left)->as_u64[1];
2797 if (ip0 + 1 == (void *) sr0)
2799 sr0->protocol = ip0->protocol;
2800 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2804 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2805 sr0->protocol = ip_ext->next_hdr;
2806 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2809 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2810 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2812 sr_policy_rewrite_trace_t *tr =
2813 vlib_add_trace (vm, node, b0, sizeof (*tr));
2814 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2815 sizeof (tr->src.as_u8));
2816 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2817 sizeof (tr->dst.as_u8));
2822 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2823 n_left_to_next, bi0, next0);
2826 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2829 /* Update counters */
2830 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2831 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2833 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2834 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2836 return from_frame->n_vectors;
2840 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2841 .function = sr_policy_rewrite_b_insert,
2842 .name = "sr-pl-rewrite-b-insert",
2843 .vector_size = sizeof (u32),
2844 .format_trace = format_sr_policy_rewrite_trace,
2845 .type = VLIB_NODE_TYPE_INTERNAL,
2846 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2847 .error_strings = sr_policy_rewrite_error_strings,
2848 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2850 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2851 foreach_sr_policy_rewrite_next
2858 * @brief Function BSID encapsulation
2860 static_always_inline void
2861 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2864 ip6_sr_header_t * sr0, u32 * next0)
2866 ip6_address_t *new_dst0;
2868 if (PREDICT_FALSE (!sr0))
2869 goto error_bsid_encaps;
2871 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2873 if (PREDICT_TRUE (sr0->segments_left != 0))
2875 sr0->segments_left -= 1;
2876 new_dst0 = (ip6_address_t *) (sr0->segments);
2877 new_dst0 += sr0->segments_left;
2878 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2879 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2885 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2886 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2890 * @brief Graph node for applying a SR policy BSID - Encapsulation
2893 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2894 vlib_frame_t * from_frame)
2896 ip6_sr_main_t *sm = &sr_main;
2897 u32 n_left_from, next_index, *from, *to_next;
2899 from = vlib_frame_vector_args (from_frame);
2900 n_left_from = from_frame->n_vectors;
2902 next_index = node->cached_next_index;
2904 int encap_pkts = 0, bsid_pkts = 0;
2906 while (n_left_from > 0)
2910 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2913 while (n_left_from >= 8 && n_left_to_next >= 4)
2915 u32 bi0, bi1, bi2, bi3;
2916 vlib_buffer_t *b0, *b1, *b2, *b3;
2917 u32 next0, next1, next2, next3;
2918 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2919 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2920 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2921 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2922 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2923 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2925 /* Prefetch next iteration. */
2927 vlib_buffer_t *p4, *p5, *p6, *p7;
2929 p4 = vlib_get_buffer (vm, from[4]);
2930 p5 = vlib_get_buffer (vm, from[5]);
2931 p6 = vlib_get_buffer (vm, from[6]);
2932 p7 = vlib_get_buffer (vm, from[7]);
2934 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2935 vlib_prefetch_buffer_header (p4, LOAD);
2936 vlib_prefetch_buffer_header (p5, LOAD);
2937 vlib_prefetch_buffer_header (p6, LOAD);
2938 vlib_prefetch_buffer_header (p7, LOAD);
2940 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2941 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2942 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2943 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2946 to_next[0] = bi0 = from[0];
2947 to_next[1] = bi1 = from[1];
2948 to_next[2] = bi2 = from[2];
2949 to_next[3] = bi3 = from[3];
2953 n_left_to_next -= 4;
2955 b0 = vlib_get_buffer (vm, bi0);
2956 b1 = vlib_get_buffer (vm, bi1);
2957 b2 = vlib_get_buffer (vm, bi2);
2958 b3 = vlib_get_buffer (vm, bi3);
2961 pool_elt_at_index (sm->sid_lists,
2962 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2964 pool_elt_at_index (sm->sid_lists,
2965 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2967 pool_elt_at_index (sm->sid_lists,
2968 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2970 pool_elt_at_index (sm->sid_lists,
2971 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2972 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2973 vec_len (sl0->rewrite));
2974 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2975 vec_len (sl1->rewrite));
2976 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977 vec_len (sl2->rewrite));
2978 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2979 vec_len (sl3->rewrite));
2981 ip0_encap = vlib_buffer_get_current (b0);
2982 ip1_encap = vlib_buffer_get_current (b1);
2983 ip2_encap = vlib_buffer_get_current (b2);
2984 ip3_encap = vlib_buffer_get_current (b3);
2986 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2987 IP_PROTOCOL_IPV6_ROUTE);
2988 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2989 IP_PROTOCOL_IPV6_ROUTE);
2990 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2991 IP_PROTOCOL_IPV6_ROUTE);
2992 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2993 IP_PROTOCOL_IPV6_ROUTE);
2995 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2996 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2997 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2998 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3000 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3001 sl0->rewrite, vec_len (sl0->rewrite));
3002 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3003 sl1->rewrite, vec_len (sl1->rewrite));
3004 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3005 sl2->rewrite, vec_len (sl2->rewrite));
3006 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3007 sl3->rewrite, vec_len (sl3->rewrite));
3009 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3010 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3011 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3012 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3014 ip0 = vlib_buffer_get_current (b0);
3015 ip1 = vlib_buffer_get_current (b1);
3016 ip2 = vlib_buffer_get_current (b2);
3017 ip3 = vlib_buffer_get_current (b3);
3019 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3020 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3021 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3022 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3024 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3026 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3028 sr_policy_rewrite_trace_t *tr =
3029 vlib_add_trace (vm, node, b0, sizeof (*tr));
3030 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3031 sizeof (tr->src.as_u8));
3032 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3033 sizeof (tr->dst.as_u8));
3036 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3038 sr_policy_rewrite_trace_t *tr =
3039 vlib_add_trace (vm, node, b1, sizeof (*tr));
3040 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3041 sizeof (tr->src.as_u8));
3042 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3043 sizeof (tr->dst.as_u8));
3046 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3048 sr_policy_rewrite_trace_t *tr =
3049 vlib_add_trace (vm, node, b2, sizeof (*tr));
3050 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3051 sizeof (tr->src.as_u8));
3052 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3053 sizeof (tr->dst.as_u8));
3056 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3058 sr_policy_rewrite_trace_t *tr =
3059 vlib_add_trace (vm, node, b3, sizeof (*tr));
3060 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3061 sizeof (tr->src.as_u8));
3062 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3063 sizeof (tr->dst.as_u8));
3068 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3069 n_left_to_next, bi0, bi1, bi2, bi3,
3070 next0, next1, next2, next3);
3073 /* Single loop for potentially the last three packets */
3074 while (n_left_from > 0 && n_left_to_next > 0)
3078 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3079 ip6_ext_header_t *prev0;
3080 ip6_sr_header_t *sr0;
3082 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3089 n_left_to_next -= 1;
3090 b0 = vlib_get_buffer (vm, bi0);
3093 pool_elt_at_index (sm->sid_lists,
3094 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3095 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3096 vec_len (sl0->rewrite));
3098 ip0_encap = vlib_buffer_get_current (b0);
3099 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3100 IP_PROTOCOL_IPV6_ROUTE);
3101 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3103 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3104 sl0->rewrite, vec_len (sl0->rewrite));
3105 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3107 ip0 = vlib_buffer_get_current (b0);
3109 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3111 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3112 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3114 sr_policy_rewrite_trace_t *tr =
3115 vlib_add_trace (vm, node, b0, sizeof (*tr));
3116 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3117 sizeof (tr->src.as_u8));
3118 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3119 sizeof (tr->dst.as_u8));
3123 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3124 n_left_to_next, bi0, next0);
3127 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3130 /* Update counters */
3131 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3132 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3134 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3135 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3138 return from_frame->n_vectors;
3142 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3143 .function = sr_policy_rewrite_b_encaps,
3144 .name = "sr-pl-rewrite-b-encaps",
3145 .vector_size = sizeof (u32),
3146 .format_trace = format_sr_policy_rewrite_trace,
3147 .type = VLIB_NODE_TYPE_INTERNAL,
3148 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3149 .error_strings = sr_policy_rewrite_error_strings,
3150 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3152 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3153 foreach_sr_policy_rewrite_next
3159 /*************************** SR Segment Lists DPOs ****************************/
3161 format_sr_segment_list_dpo (u8 * s, va_list * args)
3163 ip6_sr_main_t *sm = &sr_main;
3164 ip6_address_t *addr;
3167 index_t index = va_arg (*args, index_t);
3168 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3169 s = format (s, "SR: Segment List index:[%d]", index);
3170 s = format (s, "\n\tSegments:");
3172 sl = pool_elt_at_index (sm->sid_lists, index);
3174 s = format (s, "< ");
3175 vec_foreach (addr, sl->segments)
3177 s = format (s, "%U, ", format_ip6_address, addr);
3179 s = format (s, "\b\b > - ");
3180 s = format (s, "Weight: %u", sl->weight);
3185 const static dpo_vft_t sr_policy_rewrite_vft = {
3186 .dv_lock = sr_dpo_lock,
3187 .dv_unlock = sr_dpo_unlock,
3188 .dv_format = format_sr_segment_list_dpo,
3191 const static char *const sr_pr_encaps_ip6_nodes[] = {
3192 "sr-pl-rewrite-encaps",
3196 const static char *const sr_pr_encaps_ip4_nodes[] = {
3197 "sr-pl-rewrite-encaps-v4",
3201 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3202 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3203 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3206 const static char *const sr_pr_insert_ip6_nodes[] = {
3207 "sr-pl-rewrite-insert",
3211 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3212 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3215 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3216 "sr-pl-rewrite-b-insert",
3220 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3221 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3224 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3225 "sr-pl-rewrite-b-encaps",
3229 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3230 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3233 /********************* SR Policy Rewrite initialization ***********************/
3235 * @brief SR Policy Rewrite initialization
3238 sr_policy_rewrite_init (vlib_main_t * vm)
3240 ip6_sr_main_t *sm = &sr_main;
3242 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3243 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3244 sizeof (ip6_address_t));
3246 /* Init SR VPO DPOs type */
3247 sr_pr_encaps_dpo_type =
3248 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3250 sr_pr_insert_dpo_type =
3251 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3253 sr_pr_bsid_encaps_dpo_type =
3254 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3256 sr_pr_bsid_insert_dpo_type =
3257 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3259 /* Register the L2 encaps node used in HW redirect */
3260 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3262 sm->fib_table_ip6 = (u32) ~ 0;
3263 sm->fib_table_ip4 = (u32) ~ 0;
3268 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3272 * fd.io coding-style-patch-verification: ON
3275 * eval: (c-set-style "gnu")