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);
891 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
896 return clib_error_return (0, "No SL modification specified");
897 if (operation != 1 && sl_index == (u32) ~ 0)
898 return clib_error_return (0, "No Segment List index specified");
899 if (operation == 1 && vec_len (segments) == 0)
900 return clib_error_return (0, "No Segment List specified");
901 if (operation == 3 && weight == (u32) ~ 0)
902 return clib_error_return (0, "No new weight for the SL specified");
903 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
904 sr_policy_index, fib_table, operation, segments,
915 return clib_error_return (0,
916 "There is already a FIB entry for the BindingSID address.\n"
917 "The SR policy could not be created.");
919 return clib_error_return (0, "The specified FIB table does not exist.");
921 return clib_error_return (0,
922 "The selected SR policy only contains ONE segment list. "
923 "Please remove the SR policy instead");
925 return clib_error_return (0,
926 "Could not delete the segment list. "
927 "It is not associated with that SR policy.");
929 return clib_error_return (0,
930 "Could not modify the segment list. "
931 "The given SL is not associated with such SR policy.");
933 return clib_error_return (0, "BUG: sr policy returns %d", rv);
939 VLIB_CLI_COMMAND (sr_policy_command, static) = {
941 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
942 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
944 "Manipulation of SR policies.\n"
945 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
946 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
947 "Segment Routing policies might be of type encapsulation or srh insertion\n"
948 "Each SR policy will be associated with a unique BindingSID.\n"
949 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
950 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
951 "The add command will create a SR policy with its first segment list (sl)\n"
952 "The mod command allows you to add, remove, or modify the existing segment lists\n"
953 "within an SR policy.\n"
954 "The del command allows you to delete a SR policy along with all its associated\n"
956 .function = sr_policy_command_fn,
961 * @brief CLI to display onscreen all the SR policies
963 static clib_error_t *
964 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
965 vlib_cli_command_t * cmd)
967 ip6_sr_main_t *sm = &sr_main;
969 ip6_sr_sl_t *segment_list = 0;
970 ip6_sr_policy_t *sr_policy = 0;
971 ip6_sr_policy_t **vec_policies = 0;
976 vlib_cli_output (vm, "SR policies:");
979 pool_foreach (sr_policy, sm->sr_policies,
980 {vec_add1 (vec_policies, sr_policy); } );
983 vec_foreach_index (i, vec_policies)
985 sr_policy = vec_policies[i];
986 vlib_cli_output (vm, "[%u].-\tBSID: %U",
987 (u32) (sr_policy - sm->sr_policies),
988 format_ip6_address, &sr_policy->bsid);
989 vlib_cli_output (vm, "\tBehavior: %s",
990 (sr_policy->is_encap ? "Encapsulation" :
992 vlib_cli_output (vm, "\tType: %s",
994 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
995 vlib_cli_output (vm, "\tFIB table: %u",
996 (sr_policy->fib_table !=
997 (u32) ~ 0 ? sr_policy->fib_table : 0));
998 vlib_cli_output (vm, "\tSegment Lists:");
999 vec_foreach (sl_index, sr_policy->segments_lists)
1002 s = format (s, "\t[%u].- ", *sl_index);
1003 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1004 s = format (s, "< ");
1005 vec_foreach (addr, segment_list->segments)
1007 s = format (s, "%U, ", format_ip6_address, addr);
1009 s = format (s, "\b\b > ");
1010 s = format (s, "weight: %u", segment_list->weight);
1011 vlib_cli_output (vm, " %s", s);
1013 vlib_cli_output (vm, "-----------");
1019 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1020 .path = "show sr policies",
1021 .short_help = "show sr policies",
1022 .function = show_sr_policies_command_fn,
1026 /*************************** SR rewrite graph node ****************************/
1028 * @brief Trace for the SR Policy Rewrite graph node
1031 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1034 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1035 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1036 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1039 (s, "SR-policy-rewrite: src %U dst %U",
1040 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1046 * @brief IPv6 encapsulation processing as per RFC2473
1048 static_always_inline void
1049 encaps_processing_v6 (vlib_node_runtime_t * node,
1051 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1055 ip0_encap->hop_limit -= 1;
1057 ip0->payload_length + sizeof (ip6_header_t) +
1058 clib_net_to_host_u16 (ip0_encap->payload_length);
1059 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1060 ip0->ip_version_traffic_class_and_flow_label =
1061 ip0_encap->ip_version_traffic_class_and_flow_label;
1065 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1068 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1069 vlib_frame_t * from_frame)
1071 ip6_sr_main_t *sm = &sr_main;
1072 u32 n_left_from, next_index, *from, *to_next;
1074 from = vlib_frame_vector_args (from_frame);
1075 n_left_from = from_frame->n_vectors;
1077 next_index = node->cached_next_index;
1079 int encap_pkts = 0, bsid_pkts = 0;
1081 while (n_left_from > 0)
1085 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1088 while (n_left_from >= 8 && n_left_to_next >= 4)
1090 u32 bi0, bi1, bi2, bi3;
1091 vlib_buffer_t *b0, *b1, *b2, *b3;
1092 u32 next0, next1, next2, next3;
1093 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1094 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1095 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1096 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1098 /* Prefetch next iteration. */
1100 vlib_buffer_t *p4, *p5, *p6, *p7;
1102 p4 = vlib_get_buffer (vm, from[4]);
1103 p5 = vlib_get_buffer (vm, from[5]);
1104 p6 = vlib_get_buffer (vm, from[6]);
1105 p7 = vlib_get_buffer (vm, from[7]);
1107 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1108 vlib_prefetch_buffer_header (p4, LOAD);
1109 vlib_prefetch_buffer_header (p5, LOAD);
1110 vlib_prefetch_buffer_header (p6, LOAD);
1111 vlib_prefetch_buffer_header (p7, LOAD);
1113 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1114 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1115 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1116 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1119 to_next[0] = bi0 = from[0];
1120 to_next[1] = bi1 = from[1];
1121 to_next[2] = bi2 = from[2];
1122 to_next[3] = bi3 = from[3];
1126 n_left_to_next -= 4;
1128 b0 = vlib_get_buffer (vm, bi0);
1129 b1 = vlib_get_buffer (vm, bi1);
1130 b2 = vlib_get_buffer (vm, bi2);
1131 b3 = vlib_get_buffer (vm, bi3);
1134 pool_elt_at_index (sm->sid_lists,
1135 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1137 pool_elt_at_index (sm->sid_lists,
1138 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1140 pool_elt_at_index (sm->sid_lists,
1141 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1143 pool_elt_at_index (sm->sid_lists,
1144 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1146 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1147 vec_len (sl0->rewrite));
1148 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1149 vec_len (sl1->rewrite));
1150 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1151 vec_len (sl2->rewrite));
1152 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1153 vec_len (sl3->rewrite));
1155 ip0_encap = vlib_buffer_get_current (b0);
1156 ip1_encap = vlib_buffer_get_current (b1);
1157 ip2_encap = vlib_buffer_get_current (b2);
1158 ip3_encap = vlib_buffer_get_current (b3);
1160 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1161 sl0->rewrite, vec_len (sl0->rewrite));
1162 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1163 sl1->rewrite, vec_len (sl1->rewrite));
1164 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1165 sl2->rewrite, vec_len (sl2->rewrite));
1166 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1167 sl3->rewrite, vec_len (sl3->rewrite));
1169 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1170 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1171 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1172 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1174 ip0 = vlib_buffer_get_current (b0);
1175 ip1 = vlib_buffer_get_current (b1);
1176 ip2 = vlib_buffer_get_current (b2);
1177 ip3 = vlib_buffer_get_current (b3);
1179 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1180 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1181 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1182 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1184 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1186 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1188 sr_policy_rewrite_trace_t *tr =
1189 vlib_add_trace (vm, node, b0, sizeof (*tr));
1190 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1191 sizeof (tr->src.as_u8));
1192 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1193 sizeof (tr->dst.as_u8));
1196 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1198 sr_policy_rewrite_trace_t *tr =
1199 vlib_add_trace (vm, node, b1, sizeof (*tr));
1200 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1201 sizeof (tr->src.as_u8));
1202 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1203 sizeof (tr->dst.as_u8));
1206 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1208 sr_policy_rewrite_trace_t *tr =
1209 vlib_add_trace (vm, node, b2, sizeof (*tr));
1210 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1211 sizeof (tr->src.as_u8));
1212 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1213 sizeof (tr->dst.as_u8));
1216 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1218 sr_policy_rewrite_trace_t *tr =
1219 vlib_add_trace (vm, node, b3, sizeof (*tr));
1220 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1221 sizeof (tr->src.as_u8));
1222 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1223 sizeof (tr->dst.as_u8));
1228 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1229 n_left_to_next, bi0, bi1, bi2, bi3,
1230 next0, next1, next2, next3);
1233 /* Single loop for potentially the last three packets */
1234 while (n_left_from > 0 && n_left_to_next > 0)
1238 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1240 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1247 n_left_to_next -= 1;
1248 b0 = vlib_get_buffer (vm, bi0);
1251 pool_elt_at_index (sm->sid_lists,
1252 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1253 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1254 vec_len (sl0->rewrite));
1256 ip0_encap = vlib_buffer_get_current (b0);
1258 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1259 sl0->rewrite, vec_len (sl0->rewrite));
1260 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1262 ip0 = vlib_buffer_get_current (b0);
1264 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1266 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1267 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1269 sr_policy_rewrite_trace_t *tr =
1270 vlib_add_trace (vm, node, b0, sizeof (*tr));
1271 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1272 sizeof (tr->src.as_u8));
1273 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1274 sizeof (tr->dst.as_u8));
1278 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1279 n_left_to_next, bi0, next0);
1282 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1285 /* Update counters */
1286 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1287 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1289 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1290 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1293 return from_frame->n_vectors;
1297 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1298 .function = sr_policy_rewrite_encaps,
1299 .name = "sr-pl-rewrite-encaps",
1300 .vector_size = sizeof (u32),
1301 .format_trace = format_sr_policy_rewrite_trace,
1302 .type = VLIB_NODE_TYPE_INTERNAL,
1303 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1304 .error_strings = sr_policy_rewrite_error_strings,
1305 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1307 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1308 foreach_sr_policy_rewrite_next
1315 * @brief IPv4 encapsulation processing as per RFC2473
1317 static_always_inline void
1318 encaps_processing_v4 (vlib_node_runtime_t * node,
1320 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1323 ip6_sr_header_t *sr0;
1327 /* Inner IPv4: Decrement TTL & update checksum */
1328 ip0_encap->ttl -= 1;
1329 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1330 checksum0 += checksum0 >= 0xffff;
1331 ip0_encap->checksum = checksum0;
1333 /* Outer IPv6: Update length, FL, proto */
1334 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1335 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1336 ip0->ip_version_traffic_class_and_flow_label =
1337 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1338 ((ip0_encap->tos & 0xFF) << 20));
1339 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1341 sr0 = (void *) (ip0 + 1);
1342 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1345 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1349 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1352 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1353 vlib_frame_t * from_frame)
1355 ip6_sr_main_t *sm = &sr_main;
1356 u32 n_left_from, next_index, *from, *to_next;
1358 from = vlib_frame_vector_args (from_frame);
1359 n_left_from = from_frame->n_vectors;
1361 next_index = node->cached_next_index;
1363 int encap_pkts = 0, bsid_pkts = 0;
1365 while (n_left_from > 0)
1369 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1372 while (n_left_from >= 8 && n_left_to_next >= 4)
1374 u32 bi0, bi1, bi2, bi3;
1375 vlib_buffer_t *b0, *b1, *b2, *b3;
1376 u32 next0, next1, next2, next3;
1377 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1378 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1379 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1380 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1382 /* Prefetch next iteration. */
1384 vlib_buffer_t *p4, *p5, *p6, *p7;
1386 p4 = vlib_get_buffer (vm, from[4]);
1387 p5 = vlib_get_buffer (vm, from[5]);
1388 p6 = vlib_get_buffer (vm, from[6]);
1389 p7 = vlib_get_buffer (vm, from[7]);
1391 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1392 vlib_prefetch_buffer_header (p4, LOAD);
1393 vlib_prefetch_buffer_header (p5, LOAD);
1394 vlib_prefetch_buffer_header (p6, LOAD);
1395 vlib_prefetch_buffer_header (p7, LOAD);
1397 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1398 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1399 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1400 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1403 to_next[0] = bi0 = from[0];
1404 to_next[1] = bi1 = from[1];
1405 to_next[2] = bi2 = from[2];
1406 to_next[3] = bi3 = from[3];
1410 n_left_to_next -= 4;
1412 b0 = vlib_get_buffer (vm, bi0);
1413 b1 = vlib_get_buffer (vm, bi1);
1414 b2 = vlib_get_buffer (vm, bi2);
1415 b3 = vlib_get_buffer (vm, bi3);
1418 pool_elt_at_index (sm->sid_lists,
1419 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1421 pool_elt_at_index (sm->sid_lists,
1422 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1424 pool_elt_at_index (sm->sid_lists,
1425 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1427 pool_elt_at_index (sm->sid_lists,
1428 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1429 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1430 vec_len (sl0->rewrite));
1431 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1432 vec_len (sl1->rewrite));
1433 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1434 vec_len (sl2->rewrite));
1435 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1436 vec_len (sl3->rewrite));
1438 ip0_encap = vlib_buffer_get_current (b0);
1439 ip1_encap = vlib_buffer_get_current (b1);
1440 ip2_encap = vlib_buffer_get_current (b2);
1441 ip3_encap = vlib_buffer_get_current (b3);
1443 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1444 sl0->rewrite, vec_len (sl0->rewrite));
1445 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1446 sl1->rewrite, vec_len (sl1->rewrite));
1447 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1448 sl2->rewrite, vec_len (sl2->rewrite));
1449 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1450 sl3->rewrite, vec_len (sl3->rewrite));
1452 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1453 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1454 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1455 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1457 ip0 = vlib_buffer_get_current (b0);
1458 ip1 = vlib_buffer_get_current (b1);
1459 ip2 = vlib_buffer_get_current (b2);
1460 ip3 = vlib_buffer_get_current (b3);
1462 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1463 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1464 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1465 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1467 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1469 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1471 sr_policy_rewrite_trace_t *tr =
1472 vlib_add_trace (vm, node, b0, sizeof (*tr));
1473 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1474 sizeof (tr->src.as_u8));
1475 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1476 sizeof (tr->dst.as_u8));
1479 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1481 sr_policy_rewrite_trace_t *tr =
1482 vlib_add_trace (vm, node, b1, sizeof (*tr));
1483 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1484 sizeof (tr->src.as_u8));
1485 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1486 sizeof (tr->dst.as_u8));
1489 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1491 sr_policy_rewrite_trace_t *tr =
1492 vlib_add_trace (vm, node, b2, sizeof (*tr));
1493 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1494 sizeof (tr->src.as_u8));
1495 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1496 sizeof (tr->dst.as_u8));
1499 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1501 sr_policy_rewrite_trace_t *tr =
1502 vlib_add_trace (vm, node, b3, sizeof (*tr));
1503 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1504 sizeof (tr->src.as_u8));
1505 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1506 sizeof (tr->dst.as_u8));
1511 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1512 n_left_to_next, bi0, bi1, bi2, bi3,
1513 next0, next1, next2, next3);
1516 /* Single loop for potentially the last three packets */
1517 while (n_left_from > 0 && n_left_to_next > 0)
1521 ip6_header_t *ip0 = 0;
1522 ip4_header_t *ip0_encap = 0;
1524 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1531 n_left_to_next -= 1;
1532 b0 = vlib_get_buffer (vm, bi0);
1535 pool_elt_at_index (sm->sid_lists,
1536 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1537 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1538 vec_len (sl0->rewrite));
1540 ip0_encap = vlib_buffer_get_current (b0);
1542 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1543 sl0->rewrite, vec_len (sl0->rewrite));
1544 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1546 ip0 = vlib_buffer_get_current (b0);
1548 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1550 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1551 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1553 sr_policy_rewrite_trace_t *tr =
1554 vlib_add_trace (vm, node, b0, sizeof (*tr));
1555 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1556 sizeof (tr->src.as_u8));
1557 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1558 sizeof (tr->dst.as_u8));
1562 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1563 n_left_to_next, bi0, next0);
1566 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1569 /* Update counters */
1570 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1571 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1573 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1574 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1577 return from_frame->n_vectors;
1581 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1582 .function = sr_policy_rewrite_encaps_v4,
1583 .name = "sr-pl-rewrite-encaps-v4",
1584 .vector_size = sizeof (u32),
1585 .format_trace = format_sr_policy_rewrite_trace,
1586 .type = VLIB_NODE_TYPE_INTERNAL,
1587 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1588 .error_strings = sr_policy_rewrite_error_strings,
1589 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1591 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1592 foreach_sr_policy_rewrite_next
1599 ip_flow_hash (void *data)
1601 ip4_header_t *iph = (ip4_header_t *) data;
1603 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1604 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1606 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1612 return (*((u64 *) m) & 0xffffffffffff);
1616 l2_flow_hash (vlib_buffer_t * b0)
1618 ethernet_header_t *eh;
1620 uword is_ip, eh_size;
1623 eh = vlib_buffer_get_current (b0);
1624 eh_type = clib_net_to_host_u16 (eh->type);
1625 eh_size = ethernet_buffer_header_size (b0);
1627 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1629 /* since we have 2 cache lines, use them */
1631 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1635 b = mac_to_u64 ((u8 *) eh->dst_address);
1636 c = mac_to_u64 ((u8 *) eh->src_address);
1637 hash_mix64 (a, b, c);
1643 * @brief Graph node for applying a SR policy into a L2 frame
1646 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1647 vlib_frame_t * from_frame)
1649 ip6_sr_main_t *sm = &sr_main;
1650 u32 n_left_from, next_index, *from, *to_next;
1652 from = vlib_frame_vector_args (from_frame);
1653 n_left_from = from_frame->n_vectors;
1655 next_index = node->cached_next_index;
1657 int encap_pkts = 0, bsid_pkts = 0;
1659 while (n_left_from > 0)
1663 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1666 while (n_left_from >= 8 && n_left_to_next >= 4)
1668 u32 bi0, bi1, bi2, bi3;
1669 vlib_buffer_t *b0, *b1, *b2, *b3;
1670 u32 next0, next1, next2, next3;
1671 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1672 ethernet_header_t *en0, *en1, *en2, *en3;
1673 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1674 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1675 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1676 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1678 /* Prefetch next iteration. */
1680 vlib_buffer_t *p4, *p5, *p6, *p7;
1682 p4 = vlib_get_buffer (vm, from[4]);
1683 p5 = vlib_get_buffer (vm, from[5]);
1684 p6 = vlib_get_buffer (vm, from[6]);
1685 p7 = vlib_get_buffer (vm, from[7]);
1687 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1688 vlib_prefetch_buffer_header (p4, LOAD);
1689 vlib_prefetch_buffer_header (p5, LOAD);
1690 vlib_prefetch_buffer_header (p6, LOAD);
1691 vlib_prefetch_buffer_header (p7, LOAD);
1693 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1694 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1695 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1696 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1699 to_next[0] = bi0 = from[0];
1700 to_next[1] = bi1 = from[1];
1701 to_next[2] = bi2 = from[2];
1702 to_next[3] = bi3 = from[3];
1706 n_left_to_next -= 4;
1708 b0 = vlib_get_buffer (vm, bi0);
1709 b1 = vlib_get_buffer (vm, bi1);
1710 b2 = vlib_get_buffer (vm, bi2);
1711 b3 = vlib_get_buffer (vm, bi3);
1713 sp0 = pool_elt_at_index (sm->sr_policies,
1714 sm->sw_iface_sr_policies[vnet_buffer
1718 sp1 = pool_elt_at_index (sm->sr_policies,
1719 sm->sw_iface_sr_policies[vnet_buffer
1723 sp2 = pool_elt_at_index (sm->sr_policies,
1724 sm->sw_iface_sr_policies[vnet_buffer
1728 sp3 = pool_elt_at_index (sm->sr_policies,
1729 sm->sw_iface_sr_policies[vnet_buffer
1733 if (vec_len (sp0->segments_lists) == 1)
1734 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1737 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1738 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1739 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1740 (vec_len (sp0->segments_lists) - 1))];
1743 if (vec_len (sp1->segments_lists) == 1)
1744 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1747 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1748 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1749 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1750 (vec_len (sp1->segments_lists) - 1))];
1753 if (vec_len (sp2->segments_lists) == 1)
1754 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1757 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1758 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1759 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1760 (vec_len (sp2->segments_lists) - 1))];
1763 if (vec_len (sp3->segments_lists) == 1)
1764 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1767 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1768 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1769 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1770 (vec_len (sp3->segments_lists) - 1))];
1774 pool_elt_at_index (sm->sid_lists,
1775 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1777 pool_elt_at_index (sm->sid_lists,
1778 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1780 pool_elt_at_index (sm->sid_lists,
1781 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1783 pool_elt_at_index (sm->sid_lists,
1784 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1786 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1787 vec_len (sl0->rewrite));
1788 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1789 vec_len (sl1->rewrite));
1790 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1791 vec_len (sl2->rewrite));
1792 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1793 vec_len (sl3->rewrite));
1795 en0 = vlib_buffer_get_current (b0);
1796 en1 = vlib_buffer_get_current (b1);
1797 en2 = vlib_buffer_get_current (b2);
1798 en3 = vlib_buffer_get_current (b3);
1800 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1801 vec_len (sl0->rewrite));
1802 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1803 vec_len (sl1->rewrite));
1804 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1805 vec_len (sl2->rewrite));
1806 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1807 vec_len (sl3->rewrite));
1809 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1810 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1811 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1812 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1814 ip0 = vlib_buffer_get_current (b0);
1815 ip1 = vlib_buffer_get_current (b1);
1816 ip2 = vlib_buffer_get_current (b2);
1817 ip3 = vlib_buffer_get_current (b3);
1819 ip0->payload_length =
1820 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1821 ip1->payload_length =
1822 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1823 ip2->payload_length =
1824 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1825 ip3->payload_length =
1826 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1828 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1830 sr0 = (void *) (ip0 + 1);
1831 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1834 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1836 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1838 sr1 = (void *) (ip1 + 1);
1839 sr1->protocol = IP_PROTOCOL_IP6_NONXT;
1842 ip1->protocol = IP_PROTOCOL_IP6_NONXT;
1844 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1846 sr2 = (void *) (ip2 + 1);
1847 sr2->protocol = IP_PROTOCOL_IP6_NONXT;
1850 ip2->protocol = IP_PROTOCOL_IP6_NONXT;
1852 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1854 sr3 = (void *) (ip3 + 1);
1855 sr3->protocol = IP_PROTOCOL_IP6_NONXT;
1858 ip3->protocol = IP_PROTOCOL_IP6_NONXT;
1860 /* Which Traffic class and flow label do I set ? */
1861 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1863 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1865 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1867 sr_policy_rewrite_trace_t *tr =
1868 vlib_add_trace (vm, node, b0, sizeof (*tr));
1869 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1870 sizeof (tr->src.as_u8));
1871 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1872 sizeof (tr->dst.as_u8));
1875 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1877 sr_policy_rewrite_trace_t *tr =
1878 vlib_add_trace (vm, node, b1, sizeof (*tr));
1879 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1880 sizeof (tr->src.as_u8));
1881 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1882 sizeof (tr->dst.as_u8));
1885 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1887 sr_policy_rewrite_trace_t *tr =
1888 vlib_add_trace (vm, node, b2, sizeof (*tr));
1889 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1890 sizeof (tr->src.as_u8));
1891 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1892 sizeof (tr->dst.as_u8));
1895 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1897 sr_policy_rewrite_trace_t *tr =
1898 vlib_add_trace (vm, node, b3, sizeof (*tr));
1899 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1900 sizeof (tr->src.as_u8));
1901 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1902 sizeof (tr->dst.as_u8));
1907 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1908 n_left_to_next, bi0, bi1, bi2, bi3,
1909 next0, next1, next2, next3);
1912 /* Single loop for potentially the last three packets */
1913 while (n_left_from > 0 && n_left_to_next > 0)
1917 ip6_header_t *ip0 = 0;
1918 ip6_sr_header_t *sr0;
1919 ethernet_header_t *en0;
1920 ip6_sr_policy_t *sp0;
1922 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1929 n_left_to_next -= 1;
1930 b0 = vlib_get_buffer (vm, bi0);
1932 /* Find the SR policy */
1933 sp0 = pool_elt_at_index (sm->sr_policies,
1934 sm->sw_iface_sr_policies[vnet_buffer
1938 /* In case there is more than one SL, LB among them */
1939 if (vec_len (sp0->segments_lists) == 1)
1940 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1943 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1944 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1945 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1946 (vec_len (sp0->segments_lists) - 1))];
1949 pool_elt_at_index (sm->sid_lists,
1950 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1951 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1952 vec_len (sl0->rewrite));
1954 en0 = vlib_buffer_get_current (b0);
1956 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1957 vec_len (sl0->rewrite));
1959 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1961 ip0 = vlib_buffer_get_current (b0);
1963 ip0->payload_length =
1964 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1966 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1968 sr0 = (void *) (ip0 + 1);
1969 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1972 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1974 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1975 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1977 sr_policy_rewrite_trace_t *tr =
1978 vlib_add_trace (vm, node, b0, sizeof (*tr));
1979 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1980 sizeof (tr->src.as_u8));
1981 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1982 sizeof (tr->dst.as_u8));
1986 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1987 n_left_to_next, bi0, next0);
1990 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1993 /* Update counters */
1994 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1995 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1997 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1998 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2001 return from_frame->n_vectors;
2005 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2006 .function = sr_policy_rewrite_encaps_l2,
2007 .name = "sr-pl-rewrite-encaps-l2",
2008 .vector_size = sizeof (u32),
2009 .format_trace = format_sr_policy_rewrite_trace,
2010 .type = VLIB_NODE_TYPE_INTERNAL,
2011 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2012 .error_strings = sr_policy_rewrite_error_strings,
2013 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2015 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2016 foreach_sr_policy_rewrite_next
2023 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2026 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2027 vlib_frame_t * from_frame)
2029 ip6_sr_main_t *sm = &sr_main;
2030 u32 n_left_from, next_index, *from, *to_next;
2032 from = vlib_frame_vector_args (from_frame);
2033 n_left_from = from_frame->n_vectors;
2035 next_index = node->cached_next_index;
2037 int insert_pkts = 0, bsid_pkts = 0;
2039 while (n_left_from > 0)
2043 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2046 while (n_left_from >= 8 && n_left_to_next >= 4)
2048 u32 bi0, bi1, bi2, bi3;
2049 vlib_buffer_t *b0, *b1, *b2, *b3;
2050 u32 next0, next1, next2, next3;
2051 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2052 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2053 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2054 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2055 u16 new_l0, new_l1, new_l2, new_l3;
2057 /* Prefetch next iteration. */
2059 vlib_buffer_t *p4, *p5, *p6, *p7;
2061 p4 = vlib_get_buffer (vm, from[4]);
2062 p5 = vlib_get_buffer (vm, from[5]);
2063 p6 = vlib_get_buffer (vm, from[6]);
2064 p7 = vlib_get_buffer (vm, from[7]);
2066 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2067 vlib_prefetch_buffer_header (p4, LOAD);
2068 vlib_prefetch_buffer_header (p5, LOAD);
2069 vlib_prefetch_buffer_header (p6, LOAD);
2070 vlib_prefetch_buffer_header (p7, LOAD);
2072 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2073 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2074 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2075 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2078 to_next[0] = bi0 = from[0];
2079 to_next[1] = bi1 = from[1];
2080 to_next[2] = bi2 = from[2];
2081 to_next[3] = bi3 = from[3];
2085 n_left_to_next -= 4;
2087 b0 = vlib_get_buffer (vm, bi0);
2088 b1 = vlib_get_buffer (vm, bi1);
2089 b2 = vlib_get_buffer (vm, bi2);
2090 b3 = vlib_get_buffer (vm, bi3);
2093 pool_elt_at_index (sm->sid_lists,
2094 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2096 pool_elt_at_index (sm->sid_lists,
2097 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2099 pool_elt_at_index (sm->sid_lists,
2100 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2102 pool_elt_at_index (sm->sid_lists,
2103 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2104 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2105 vec_len (sl0->rewrite));
2106 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2107 vec_len (sl1->rewrite));
2108 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2109 vec_len (sl2->rewrite));
2110 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2111 vec_len (sl3->rewrite));
2113 ip0 = vlib_buffer_get_current (b0);
2114 ip1 = vlib_buffer_get_current (b1);
2115 ip2 = vlib_buffer_get_current (b2);
2116 ip3 = vlib_buffer_get_current (b3);
2118 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2120 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2121 ip6_ext_header_len (ip0 + 1));
2123 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2125 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2127 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2128 ip6_ext_header_len (ip1 + 1));
2130 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2132 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2134 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2135 ip6_ext_header_len (ip2 + 1));
2137 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2139 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2141 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2142 ip6_ext_header_len (ip3 + 1));
2144 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2146 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2147 (void *) sr0 - (void *) ip0);
2148 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2149 (void *) sr1 - (void *) ip1);
2150 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2151 (void *) sr2 - (void *) ip2);
2152 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2153 (void *) sr3 - (void *) ip3);
2155 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2156 vec_len (sl0->rewrite));
2157 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2158 vec_len (sl1->rewrite));
2159 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2160 vec_len (sl2->rewrite));
2161 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2162 vec_len (sl3->rewrite));
2164 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2165 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2166 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2167 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2169 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2170 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2171 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2172 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2174 ip0->hop_limit -= 1;
2175 ip1->hop_limit -= 1;
2176 ip2->hop_limit -= 1;
2177 ip3->hop_limit -= 1;
2180 clib_net_to_host_u16 (ip0->payload_length) +
2181 vec_len (sl0->rewrite);
2183 clib_net_to_host_u16 (ip1->payload_length) +
2184 vec_len (sl1->rewrite);
2186 clib_net_to_host_u16 (ip2->payload_length) +
2187 vec_len (sl2->rewrite);
2189 clib_net_to_host_u16 (ip3->payload_length) +
2190 vec_len (sl3->rewrite);
2192 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2193 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2194 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2195 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2197 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2198 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2199 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2200 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2202 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2203 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2204 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2205 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2206 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2207 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2208 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2209 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2211 ip0->dst_address.as_u64[0] =
2212 (sr0->segments + sr0->segments_left)->as_u64[0];
2213 ip0->dst_address.as_u64[1] =
2214 (sr0->segments + sr0->segments_left)->as_u64[1];
2215 ip1->dst_address.as_u64[0] =
2216 (sr1->segments + sr1->segments_left)->as_u64[0];
2217 ip1->dst_address.as_u64[1] =
2218 (sr1->segments + sr1->segments_left)->as_u64[1];
2219 ip2->dst_address.as_u64[0] =
2220 (sr2->segments + sr2->segments_left)->as_u64[0];
2221 ip2->dst_address.as_u64[1] =
2222 (sr2->segments + sr2->segments_left)->as_u64[1];
2223 ip3->dst_address.as_u64[0] =
2224 (sr3->segments + sr3->segments_left)->as_u64[0];
2225 ip3->dst_address.as_u64[1] =
2226 (sr3->segments + sr3->segments_left)->as_u64[1];
2228 ip6_ext_header_t *ip_ext;
2229 if (ip0 + 1 == (void *) sr0)
2231 sr0->protocol = ip0->protocol;
2232 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2236 ip_ext = (void *) (ip0 + 1);
2237 sr0->protocol = ip_ext->next_hdr;
2238 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2241 if (ip1 + 1 == (void *) sr1)
2243 sr1->protocol = ip1->protocol;
2244 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2248 ip_ext = (void *) (ip2 + 1);
2249 sr2->protocol = ip_ext->next_hdr;
2250 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2253 if (ip2 + 1 == (void *) sr2)
2255 sr2->protocol = ip2->protocol;
2256 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2260 ip_ext = (void *) (ip2 + 1);
2261 sr2->protocol = ip_ext->next_hdr;
2262 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2265 if (ip3 + 1 == (void *) sr3)
2267 sr3->protocol = ip3->protocol;
2268 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2272 ip_ext = (void *) (ip3 + 1);
2273 sr3->protocol = ip_ext->next_hdr;
2274 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2279 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2281 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2283 sr_policy_rewrite_trace_t *tr =
2284 vlib_add_trace (vm, node, b0, sizeof (*tr));
2285 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2286 sizeof (tr->src.as_u8));
2287 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2288 sizeof (tr->dst.as_u8));
2291 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2293 sr_policy_rewrite_trace_t *tr =
2294 vlib_add_trace (vm, node, b1, sizeof (*tr));
2295 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2296 sizeof (tr->src.as_u8));
2297 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2298 sizeof (tr->dst.as_u8));
2301 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2303 sr_policy_rewrite_trace_t *tr =
2304 vlib_add_trace (vm, node, b2, sizeof (*tr));
2305 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2306 sizeof (tr->src.as_u8));
2307 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2308 sizeof (tr->dst.as_u8));
2311 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2313 sr_policy_rewrite_trace_t *tr =
2314 vlib_add_trace (vm, node, b3, sizeof (*tr));
2315 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2316 sizeof (tr->src.as_u8));
2317 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2318 sizeof (tr->dst.as_u8));
2322 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2323 n_left_to_next, bi0, bi1, bi2, bi3,
2324 next0, next1, next2, next3);
2327 /* Single loop for potentially the last three packets */
2328 while (n_left_from > 0 && n_left_to_next > 0)
2332 ip6_header_t *ip0 = 0;
2333 ip6_sr_header_t *sr0 = 0;
2335 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2343 n_left_to_next -= 1;
2345 b0 = vlib_get_buffer (vm, bi0);
2347 pool_elt_at_index (sm->sid_lists,
2348 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2349 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2350 vec_len (sl0->rewrite));
2352 ip0 = vlib_buffer_get_current (b0);
2354 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2356 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2357 ip6_ext_header_len (ip0 + 1));
2359 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2361 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2362 (void *) sr0 - (void *) ip0);
2363 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2364 vec_len (sl0->rewrite));
2366 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2368 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2369 ip0->hop_limit -= 1;
2371 clib_net_to_host_u16 (ip0->payload_length) +
2372 vec_len (sl0->rewrite);
2373 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2375 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2376 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2377 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2379 ip0->dst_address.as_u64[0] =
2380 (sr0->segments + sr0->segments_left)->as_u64[0];
2381 ip0->dst_address.as_u64[1] =
2382 (sr0->segments + sr0->segments_left)->as_u64[1];
2384 if (ip0 + 1 == (void *) sr0)
2386 sr0->protocol = ip0->protocol;
2387 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2391 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2392 sr0->protocol = ip_ext->next_hdr;
2393 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2396 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2397 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2399 sr_policy_rewrite_trace_t *tr =
2400 vlib_add_trace (vm, node, b0, sizeof (*tr));
2401 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2402 sizeof (tr->src.as_u8));
2403 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2404 sizeof (tr->dst.as_u8));
2409 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2410 n_left_to_next, bi0, next0);
2413 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2416 /* Update counters */
2417 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2418 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2420 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2421 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2423 return from_frame->n_vectors;
2427 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2428 .function = sr_policy_rewrite_insert,
2429 .name = "sr-pl-rewrite-insert",
2430 .vector_size = sizeof (u32),
2431 .format_trace = format_sr_policy_rewrite_trace,
2432 .type = VLIB_NODE_TYPE_INTERNAL,
2433 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2434 .error_strings = sr_policy_rewrite_error_strings,
2435 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2437 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2438 foreach_sr_policy_rewrite_next
2445 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2448 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2449 vlib_frame_t * from_frame)
2451 ip6_sr_main_t *sm = &sr_main;
2452 u32 n_left_from, next_index, *from, *to_next;
2454 from = vlib_frame_vector_args (from_frame);
2455 n_left_from = from_frame->n_vectors;
2457 next_index = node->cached_next_index;
2459 int insert_pkts = 0, bsid_pkts = 0;
2461 while (n_left_from > 0)
2465 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2468 while (n_left_from >= 8 && n_left_to_next >= 4)
2470 u32 bi0, bi1, bi2, bi3;
2471 vlib_buffer_t *b0, *b1, *b2, *b3;
2472 u32 next0, next1, next2, next3;
2473 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2474 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2475 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2476 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2477 u16 new_l0, new_l1, new_l2, new_l3;
2479 /* Prefetch next iteration. */
2481 vlib_buffer_t *p4, *p5, *p6, *p7;
2483 p4 = vlib_get_buffer (vm, from[4]);
2484 p5 = vlib_get_buffer (vm, from[5]);
2485 p6 = vlib_get_buffer (vm, from[6]);
2486 p7 = vlib_get_buffer (vm, from[7]);
2488 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2489 vlib_prefetch_buffer_header (p4, LOAD);
2490 vlib_prefetch_buffer_header (p5, LOAD);
2491 vlib_prefetch_buffer_header (p6, LOAD);
2492 vlib_prefetch_buffer_header (p7, LOAD);
2494 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2495 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2496 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2497 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2500 to_next[0] = bi0 = from[0];
2501 to_next[1] = bi1 = from[1];
2502 to_next[2] = bi2 = from[2];
2503 to_next[3] = bi3 = from[3];
2507 n_left_to_next -= 4;
2509 b0 = vlib_get_buffer (vm, bi0);
2510 b1 = vlib_get_buffer (vm, bi1);
2511 b2 = vlib_get_buffer (vm, bi2);
2512 b3 = vlib_get_buffer (vm, bi3);
2515 pool_elt_at_index (sm->sid_lists,
2516 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2518 pool_elt_at_index (sm->sid_lists,
2519 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2521 pool_elt_at_index (sm->sid_lists,
2522 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2524 pool_elt_at_index (sm->sid_lists,
2525 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2526 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2527 vec_len (sl0->rewrite_bsid));
2528 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2529 vec_len (sl1->rewrite_bsid));
2530 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2531 vec_len (sl2->rewrite_bsid));
2532 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2533 vec_len (sl3->rewrite_bsid));
2535 ip0 = vlib_buffer_get_current (b0);
2536 ip1 = vlib_buffer_get_current (b1);
2537 ip2 = vlib_buffer_get_current (b2);
2538 ip3 = vlib_buffer_get_current (b3);
2540 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2542 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2543 ip6_ext_header_len (ip0 + 1));
2545 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2547 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2549 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2550 ip6_ext_header_len (ip1 + 1));
2552 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2554 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2556 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2557 ip6_ext_header_len (ip2 + 1));
2559 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2561 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2563 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2564 ip6_ext_header_len (ip3 + 1));
2566 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2568 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2569 (void *) sr0 - (void *) ip0);
2570 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2571 (void *) sr1 - (void *) ip1);
2572 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2573 (void *) sr2 - (void *) ip2);
2574 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2575 (void *) sr3 - (void *) ip3);
2577 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2578 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2579 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2580 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2581 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2582 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2583 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2584 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2586 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2587 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2588 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2589 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2591 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2592 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2593 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2594 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2596 ip0->hop_limit -= 1;
2597 ip1->hop_limit -= 1;
2598 ip2->hop_limit -= 1;
2599 ip3->hop_limit -= 1;
2602 clib_net_to_host_u16 (ip0->payload_length) +
2603 vec_len (sl0->rewrite_bsid);
2605 clib_net_to_host_u16 (ip1->payload_length) +
2606 vec_len (sl1->rewrite_bsid);
2608 clib_net_to_host_u16 (ip2->payload_length) +
2609 vec_len (sl2->rewrite_bsid);
2611 clib_net_to_host_u16 (ip3->payload_length) +
2612 vec_len (sl3->rewrite_bsid);
2614 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2615 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2616 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2617 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2619 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2620 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2621 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2622 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2624 ip0->dst_address.as_u64[0] =
2625 (sr0->segments + sr0->segments_left)->as_u64[0];
2626 ip0->dst_address.as_u64[1] =
2627 (sr0->segments + sr0->segments_left)->as_u64[1];
2628 ip1->dst_address.as_u64[0] =
2629 (sr1->segments + sr1->segments_left)->as_u64[0];
2630 ip1->dst_address.as_u64[1] =
2631 (sr1->segments + sr1->segments_left)->as_u64[1];
2632 ip2->dst_address.as_u64[0] =
2633 (sr2->segments + sr2->segments_left)->as_u64[0];
2634 ip2->dst_address.as_u64[1] =
2635 (sr2->segments + sr2->segments_left)->as_u64[1];
2636 ip3->dst_address.as_u64[0] =
2637 (sr3->segments + sr3->segments_left)->as_u64[0];
2638 ip3->dst_address.as_u64[1] =
2639 (sr3->segments + sr3->segments_left)->as_u64[1];
2641 ip6_ext_header_t *ip_ext;
2642 if (ip0 + 1 == (void *) sr0)
2644 sr0->protocol = ip0->protocol;
2645 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2649 ip_ext = (void *) (ip0 + 1);
2650 sr0->protocol = ip_ext->next_hdr;
2651 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2654 if (ip1 + 1 == (void *) sr1)
2656 sr1->protocol = ip1->protocol;
2657 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2661 ip_ext = (void *) (ip2 + 1);
2662 sr2->protocol = ip_ext->next_hdr;
2663 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2666 if (ip2 + 1 == (void *) sr2)
2668 sr2->protocol = ip2->protocol;
2669 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2673 ip_ext = (void *) (ip2 + 1);
2674 sr2->protocol = ip_ext->next_hdr;
2675 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2678 if (ip3 + 1 == (void *) sr3)
2680 sr3->protocol = ip3->protocol;
2681 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2685 ip_ext = (void *) (ip3 + 1);
2686 sr3->protocol = ip_ext->next_hdr;
2687 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2692 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2694 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2696 sr_policy_rewrite_trace_t *tr =
2697 vlib_add_trace (vm, node, b0, sizeof (*tr));
2698 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2699 sizeof (tr->src.as_u8));
2700 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2701 sizeof (tr->dst.as_u8));
2704 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2706 sr_policy_rewrite_trace_t *tr =
2707 vlib_add_trace (vm, node, b1, sizeof (*tr));
2708 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2709 sizeof (tr->src.as_u8));
2710 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2711 sizeof (tr->dst.as_u8));
2714 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2716 sr_policy_rewrite_trace_t *tr =
2717 vlib_add_trace (vm, node, b2, sizeof (*tr));
2718 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2719 sizeof (tr->src.as_u8));
2720 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2721 sizeof (tr->dst.as_u8));
2724 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2726 sr_policy_rewrite_trace_t *tr =
2727 vlib_add_trace (vm, node, b3, sizeof (*tr));
2728 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2729 sizeof (tr->src.as_u8));
2730 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2731 sizeof (tr->dst.as_u8));
2735 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2736 n_left_to_next, bi0, bi1, bi2, bi3,
2737 next0, next1, next2, next3);
2740 /* Single loop for potentially the last three packets */
2741 while (n_left_from > 0 && n_left_to_next > 0)
2745 ip6_header_t *ip0 = 0;
2746 ip6_sr_header_t *sr0 = 0;
2748 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2756 n_left_to_next -= 1;
2758 b0 = vlib_get_buffer (vm, bi0);
2760 pool_elt_at_index (sm->sid_lists,
2761 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2762 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2763 vec_len (sl0->rewrite_bsid));
2765 ip0 = vlib_buffer_get_current (b0);
2767 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2769 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2770 ip6_ext_header_len (ip0 + 1));
2772 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2774 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2775 (void *) sr0 - (void *) ip0);
2776 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2777 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2779 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2781 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2782 ip0->hop_limit -= 1;
2784 clib_net_to_host_u16 (ip0->payload_length) +
2785 vec_len (sl0->rewrite_bsid);
2786 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2788 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2790 ip0->dst_address.as_u64[0] =
2791 (sr0->segments + sr0->segments_left)->as_u64[0];
2792 ip0->dst_address.as_u64[1] =
2793 (sr0->segments + sr0->segments_left)->as_u64[1];
2795 if (ip0 + 1 == (void *) sr0)
2797 sr0->protocol = ip0->protocol;
2798 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2802 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2803 sr0->protocol = ip_ext->next_hdr;
2804 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2807 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2808 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2810 sr_policy_rewrite_trace_t *tr =
2811 vlib_add_trace (vm, node, b0, sizeof (*tr));
2812 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2813 sizeof (tr->src.as_u8));
2814 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2815 sizeof (tr->dst.as_u8));
2820 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2821 n_left_to_next, bi0, next0);
2824 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2827 /* Update counters */
2828 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2829 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2831 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2832 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2834 return from_frame->n_vectors;
2838 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2839 .function = sr_policy_rewrite_b_insert,
2840 .name = "sr-pl-rewrite-b-insert",
2841 .vector_size = sizeof (u32),
2842 .format_trace = format_sr_policy_rewrite_trace,
2843 .type = VLIB_NODE_TYPE_INTERNAL,
2844 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2845 .error_strings = sr_policy_rewrite_error_strings,
2846 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2848 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2849 foreach_sr_policy_rewrite_next
2856 * @brief Function BSID encapsulation
2858 static_always_inline void
2859 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2862 ip6_sr_header_t * sr0, u32 * next0)
2864 ip6_address_t *new_dst0;
2866 if (PREDICT_FALSE (!sr0))
2867 goto error_bsid_encaps;
2869 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2871 if (PREDICT_TRUE (sr0->segments_left != 0))
2873 sr0->segments_left -= 1;
2874 new_dst0 = (ip6_address_t *) (sr0->segments);
2875 new_dst0 += sr0->segments_left;
2876 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2877 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2883 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2884 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2888 * @brief Graph node for applying a SR policy BSID - Encapsulation
2891 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2892 vlib_frame_t * from_frame)
2894 ip6_sr_main_t *sm = &sr_main;
2895 u32 n_left_from, next_index, *from, *to_next;
2897 from = vlib_frame_vector_args (from_frame);
2898 n_left_from = from_frame->n_vectors;
2900 next_index = node->cached_next_index;
2902 int encap_pkts = 0, bsid_pkts = 0;
2904 while (n_left_from > 0)
2908 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2911 while (n_left_from >= 8 && n_left_to_next >= 4)
2913 u32 bi0, bi1, bi2, bi3;
2914 vlib_buffer_t *b0, *b1, *b2, *b3;
2915 u32 next0, next1, next2, next3;
2916 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2917 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2918 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2919 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2920 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2921 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2923 /* Prefetch next iteration. */
2925 vlib_buffer_t *p4, *p5, *p6, *p7;
2927 p4 = vlib_get_buffer (vm, from[4]);
2928 p5 = vlib_get_buffer (vm, from[5]);
2929 p6 = vlib_get_buffer (vm, from[6]);
2930 p7 = vlib_get_buffer (vm, from[7]);
2932 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2933 vlib_prefetch_buffer_header (p4, LOAD);
2934 vlib_prefetch_buffer_header (p5, LOAD);
2935 vlib_prefetch_buffer_header (p6, LOAD);
2936 vlib_prefetch_buffer_header (p7, LOAD);
2938 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2939 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2940 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2941 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2944 to_next[0] = bi0 = from[0];
2945 to_next[1] = bi1 = from[1];
2946 to_next[2] = bi2 = from[2];
2947 to_next[3] = bi3 = from[3];
2951 n_left_to_next -= 4;
2953 b0 = vlib_get_buffer (vm, bi0);
2954 b1 = vlib_get_buffer (vm, bi1);
2955 b2 = vlib_get_buffer (vm, bi2);
2956 b3 = vlib_get_buffer (vm, bi3);
2959 pool_elt_at_index (sm->sid_lists,
2960 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2962 pool_elt_at_index (sm->sid_lists,
2963 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2965 pool_elt_at_index (sm->sid_lists,
2966 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2968 pool_elt_at_index (sm->sid_lists,
2969 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2970 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2971 vec_len (sl0->rewrite));
2972 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2973 vec_len (sl1->rewrite));
2974 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2975 vec_len (sl2->rewrite));
2976 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977 vec_len (sl3->rewrite));
2979 ip0_encap = vlib_buffer_get_current (b0);
2980 ip1_encap = vlib_buffer_get_current (b1);
2981 ip2_encap = vlib_buffer_get_current (b2);
2982 ip3_encap = vlib_buffer_get_current (b3);
2984 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2985 IP_PROTOCOL_IPV6_ROUTE);
2986 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2987 IP_PROTOCOL_IPV6_ROUTE);
2988 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2989 IP_PROTOCOL_IPV6_ROUTE);
2990 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2991 IP_PROTOCOL_IPV6_ROUTE);
2993 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2994 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2995 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2996 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2998 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2999 sl0->rewrite, vec_len (sl0->rewrite));
3000 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3001 sl1->rewrite, vec_len (sl1->rewrite));
3002 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3003 sl2->rewrite, vec_len (sl2->rewrite));
3004 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3005 sl3->rewrite, vec_len (sl3->rewrite));
3007 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3008 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3009 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3010 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3012 ip0 = vlib_buffer_get_current (b0);
3013 ip1 = vlib_buffer_get_current (b1);
3014 ip2 = vlib_buffer_get_current (b2);
3015 ip3 = vlib_buffer_get_current (b3);
3017 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3018 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3019 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3020 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3022 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3024 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3026 sr_policy_rewrite_trace_t *tr =
3027 vlib_add_trace (vm, node, b0, sizeof (*tr));
3028 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3029 sizeof (tr->src.as_u8));
3030 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3031 sizeof (tr->dst.as_u8));
3034 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3036 sr_policy_rewrite_trace_t *tr =
3037 vlib_add_trace (vm, node, b1, sizeof (*tr));
3038 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3039 sizeof (tr->src.as_u8));
3040 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3041 sizeof (tr->dst.as_u8));
3044 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3046 sr_policy_rewrite_trace_t *tr =
3047 vlib_add_trace (vm, node, b2, sizeof (*tr));
3048 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3049 sizeof (tr->src.as_u8));
3050 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3051 sizeof (tr->dst.as_u8));
3054 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3056 sr_policy_rewrite_trace_t *tr =
3057 vlib_add_trace (vm, node, b3, sizeof (*tr));
3058 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3059 sizeof (tr->src.as_u8));
3060 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3061 sizeof (tr->dst.as_u8));
3066 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3067 n_left_to_next, bi0, bi1, bi2, bi3,
3068 next0, next1, next2, next3);
3071 /* Single loop for potentially the last three packets */
3072 while (n_left_from > 0 && n_left_to_next > 0)
3076 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3077 ip6_ext_header_t *prev0;
3078 ip6_sr_header_t *sr0;
3080 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3087 n_left_to_next -= 1;
3088 b0 = vlib_get_buffer (vm, bi0);
3091 pool_elt_at_index (sm->sid_lists,
3092 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3093 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3094 vec_len (sl0->rewrite));
3096 ip0_encap = vlib_buffer_get_current (b0);
3097 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3098 IP_PROTOCOL_IPV6_ROUTE);
3099 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3101 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3102 sl0->rewrite, vec_len (sl0->rewrite));
3103 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3105 ip0 = vlib_buffer_get_current (b0);
3107 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3109 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3110 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3112 sr_policy_rewrite_trace_t *tr =
3113 vlib_add_trace (vm, node, b0, sizeof (*tr));
3114 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3115 sizeof (tr->src.as_u8));
3116 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3117 sizeof (tr->dst.as_u8));
3121 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3122 n_left_to_next, bi0, next0);
3125 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3128 /* Update counters */
3129 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3130 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3132 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3133 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3136 return from_frame->n_vectors;
3140 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3141 .function = sr_policy_rewrite_b_encaps,
3142 .name = "sr-pl-rewrite-b-encaps",
3143 .vector_size = sizeof (u32),
3144 .format_trace = format_sr_policy_rewrite_trace,
3145 .type = VLIB_NODE_TYPE_INTERNAL,
3146 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3147 .error_strings = sr_policy_rewrite_error_strings,
3148 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3150 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3151 foreach_sr_policy_rewrite_next
3157 /*************************** SR Segment Lists DPOs ****************************/
3159 format_sr_segment_list_dpo (u8 * s, va_list * args)
3161 ip6_sr_main_t *sm = &sr_main;
3162 ip6_address_t *addr;
3165 index_t index = va_arg (*args, index_t);
3166 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3167 s = format (s, "SR: Segment List index:[%d]", index);
3168 s = format (s, "\n\tSegments:");
3170 sl = pool_elt_at_index (sm->sid_lists, index);
3172 s = format (s, "< ");
3173 vec_foreach (addr, sl->segments)
3175 s = format (s, "%U, ", format_ip6_address, addr);
3177 s = format (s, "\b\b > - ");
3178 s = format (s, "Weight: %u", sl->weight);
3183 const static dpo_vft_t sr_policy_rewrite_vft = {
3184 .dv_lock = sr_dpo_lock,
3185 .dv_unlock = sr_dpo_unlock,
3186 .dv_format = format_sr_segment_list_dpo,
3189 const static char *const sr_pr_encaps_ip6_nodes[] = {
3190 "sr-pl-rewrite-encaps",
3194 const static char *const sr_pr_encaps_ip4_nodes[] = {
3195 "sr-pl-rewrite-encaps-v4",
3199 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3200 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3201 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3204 const static char *const sr_pr_insert_ip6_nodes[] = {
3205 "sr-pl-rewrite-insert",
3209 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3210 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3213 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3214 "sr-pl-rewrite-b-insert",
3218 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3219 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3222 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3223 "sr-pl-rewrite-b-encaps",
3227 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3228 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3231 /********************* SR Policy Rewrite initialization ***********************/
3233 * @brief SR Policy Rewrite initialization
3236 sr_policy_rewrite_init (vlib_main_t * vm)
3238 ip6_sr_main_t *sm = &sr_main;
3240 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3241 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3242 sizeof (ip6_address_t));
3244 /* Init SR VPO DPOs type */
3245 sr_pr_encaps_dpo_type =
3246 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3248 sr_pr_insert_dpo_type =
3249 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3251 sr_pr_bsid_encaps_dpo_type =
3252 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3254 sr_pr_bsid_insert_dpo_type =
3255 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3257 /* Register the L2 encaps node used in HW redirect */
3258 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3260 sm->fib_table_ip6 = (u32) ~ 0;
3261 sm->fib_table_ip4 = (u32) ~ 0;
3266 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3270 * fd.io coding-style-patch-verification: ON
3273 * eval: (c-set-style "gnu")