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/sr/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/sr/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
115 static clib_error_t *
116 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
125 return clib_error_return (0, "No address specified");
127 return clib_error_return (0, "No address specified");
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132 .path = "set sr encaps source",
133 .short_help = "set sr encaps source addr <ip6_addr>",
134 .function = set_sr_src_command_fn,
138 /*********************** SR rewrite string computation ************************/
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
142 * @param sl is a vector of IPv6 addresses composing the Segment List
144 * @return precomputed rewrite string for encapsulation
147 compute_rewrite_encaps (ip6_address_t * sl)
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
163 vec_validate (rs, header_length - 1);
165 iph = (ip6_header_t *) rs;
166 iph->ip_version_traffic_class_and_flow_label =
167 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171 iph->protocol = IP_PROTOCOL_IPV6;
172 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
174 srh = (ip6_sr_header_t *) (iph + 1);
175 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176 srh->protocol = IP_PROTOCOL_IPV6;
177 srh->type = ROUTING_HEADER_TYPE_SR;
178 srh->segments_left = vec_len (sl) - 1;
179 srh->first_segment = vec_len (sl) - 1;
180 srh->length = ((sizeof (ip6_sr_header_t) +
181 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
196 * @brief SR rewrite string computation for SRH insertion (inline)
198 * @param sl is a vector of IPv6 addresses composing the Segment List
200 * @return precomputed rewrite string for SRH insertion
203 compute_rewrite_insert (ip6_address_t * sl)
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 srh = (ip6_sr_header_t *) rs;
217 srh->type = ROUTING_HEADER_TYPE_SR;
218 srh->segments_left = vec_len (sl);
219 srh->first_segment = vec_len (sl);
220 srh->length = ((sizeof (ip6_sr_header_t) +
221 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
236 * @param sl is a vector of IPv6 addresses composing the Segment List
238 * @return precomputed rewrite string for SRH insertion with BSID
241 compute_rewrite_bsid (ip6_address_t * sl)
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
252 vec_validate (rs, header_length - 1);
254 srh = (ip6_sr_header_t *) rs;
255 srh->type = ROUTING_HEADER_TYPE_SR;
256 srh->segments_left = vec_len (sl) - 1;
257 srh->first_segment = vec_len (sl) - 1;
258 srh->length = ((sizeof (ip6_sr_header_t) +
259 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
271 /*************************** SR LB helper functions **************************/
273 * @brief Creates a Segment List and adds it to an SR policy
275 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276 * not necessarily unique. Hence there might be two Segment List within the
277 * same SR Policy with exactly the same segments and same weight.
279 * @param sr_policy is the SR policy where the SL will be added
280 * @param sl is a vector of IPv6 addresses composing the Segment List
281 * @param weight is the weight of the SegmentList (for load-balancing purposes)
282 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
284 * @return pointer to the just created segment list
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
298 /* Fill in segment list */
299 segment_list->weight =
300 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301 segment_list->segments = vec_dup (sl);
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
321 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
322 segment_list - sm->sid_lists);
323 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
324 segment_list - sm->sid_lists);
325 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
326 DPO_PROTO_IP6, segment_list - sm->sid_lists);
330 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
331 segment_list - sm->sid_lists);
332 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
333 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 * @brief Updates the Load Balancer after an SR Policy change
342 * @param sr_policy is the modified SR Policy
345 update_lb (ip6_sr_policy_t * sr_policy)
347 flow_hash_config_t fhc;
349 ip6_sr_sl_t *segment_list;
350 ip6_sr_main_t *sm = &sr_main;
351 load_balance_path_t path;
352 path.path_index = FIB_NODE_INDEX_INVALID;
353 load_balance_path_t *ip4_path_vector = 0;
354 load_balance_path_t *ip6_path_vector = 0;
355 load_balance_path_t *b_path_vector = 0;
357 /* In case LB does not exist, create it */
358 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
361 .fp_proto = FIB_PROTOCOL_IP6,
364 .ip6 = sr_policy->bsid,
368 /* Add FIB entry for BSID */
369 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
370 dpo_proto_to_fib (DPO_PROTO_IP6));
372 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
373 load_balance_create (0, DPO_PROTO_IP6, fhc));
375 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
376 load_balance_create (0, DPO_PROTO_IP6, fhc));
378 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
379 fib_table_entry_special_dpo_update (fib_table_id_find_fib_index
381 sr_policy->fib_table), &pfx,
383 FIB_ENTRY_FLAG_EXCLUSIVE,
384 &sr_policy->bsid_dpo);
386 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
389 FIB_ENTRY_FLAG_EXCLUSIVE,
390 &sr_policy->ip6_dpo);
392 if (sr_policy->is_encap)
394 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
395 load_balance_create (0, DPO_PROTO_IP4, fhc));
397 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
400 FIB_ENTRY_FLAG_EXCLUSIVE,
401 &sr_policy->ip4_dpo);
406 /* Create the LB path vector */
407 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
408 vec_foreach (sl_index, sr_policy->segments_lists)
410 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
411 path.path_dpo = segment_list->bsid_dpo;
412 path.path_weight = segment_list->weight;
413 vec_add1 (b_path_vector, path);
414 path.path_dpo = segment_list->ip6_dpo;
415 vec_add1 (ip6_path_vector, path);
416 if (sr_policy->is_encap)
418 path.path_dpo = segment_list->ip4_dpo;
419 vec_add1 (ip4_path_vector, path);
423 /* Update LB multipath */
424 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
425 LOAD_BALANCE_FLAG_NONE);
426 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
427 LOAD_BALANCE_FLAG_NONE);
428 if (sr_policy->is_encap)
429 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
430 LOAD_BALANCE_FLAG_NONE);
433 vec_free (b_path_vector);
434 vec_free (ip6_path_vector);
435 vec_free (ip4_path_vector);
440 * @brief Updates the Replicate DPO after an SR Policy change
442 * @param sr_policy is the modified SR Policy (type spray)
445 update_replicate (ip6_sr_policy_t * sr_policy)
448 ip6_sr_sl_t *segment_list;
449 ip6_sr_main_t *sm = &sr_main;
450 load_balance_path_t path;
451 path.path_index = FIB_NODE_INDEX_INVALID;
452 load_balance_path_t *b_path_vector = 0;
453 load_balance_path_t *ip6_path_vector = 0;
454 load_balance_path_t *ip4_path_vector = 0;
456 /* In case LB does not exist, create it */
457 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
459 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
460 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
462 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
463 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
465 /* Update FIB entry's DPO to point to SR without LB */
467 .fp_proto = FIB_PROTOCOL_IP6,
470 .ip6 = sr_policy->bsid,
473 fib_table_entry_special_dpo_update (fib_table_id_find_fib_index
475 sr_policy->fib_table), &pfx,
477 FIB_ENTRY_FLAG_EXCLUSIVE,
478 &sr_policy->bsid_dpo);
480 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
483 FIB_ENTRY_FLAG_EXCLUSIVE,
484 &sr_policy->ip6_dpo);
486 if (sr_policy->is_encap)
488 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
489 replicate_create (0, DPO_PROTO_IP4));
491 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
494 FIB_ENTRY_FLAG_EXCLUSIVE,
495 &sr_policy->ip4_dpo);
500 /* Create the replicate path vector */
501 path.path_weight = 1;
502 vec_foreach (sl_index, sr_policy->segments_lists)
504 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
505 path.path_dpo = segment_list->bsid_dpo;
506 vec_add1 (b_path_vector, path);
507 path.path_dpo = segment_list->ip6_dpo;
508 vec_add1 (ip6_path_vector, path);
509 if (sr_policy->is_encap)
511 path.path_dpo = segment_list->ip4_dpo;
512 vec_add1 (ip4_path_vector, path);
516 /* Update replicate multipath */
517 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
518 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
519 if (sr_policy->is_encap)
520 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
523 vec_free (b_path_vector);
524 vec_free (ip6_path_vector);
525 vec_free (ip4_path_vector);
528 /******************************* SR rewrite API *******************************/
529 /* Three functions for handling sr policies:
533 * All of them are API. CLI function on sr_policy_command_fn */
536 * @brief Create a new SR policy
538 * @param bsid is the bindingSID of the SR Policy
539 * @param segments is a vector of IPv6 address composing the segment list
540 * @param weight is the weight of the sid list. optional.
541 * @param behavior is the behavior of the SR policy. (default//spray)
542 * @param fib_table is the VRF where to install the FIB entry for the BSID
543 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
545 * @return 0 if correct, else error
548 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
549 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
551 ip6_sr_main_t *sm = &sr_main;
552 ip6_sr_policy_t *sr_policy = 0;
555 /* Search for existing keys (BSID) */
556 p = mhash_get (&sm->sr_policies_index_hash, bsid);
559 /* Add SR policy that already exists; complain */
563 /* Search collision in FIB entries */
564 /* Explanation: It might be possible that some other entity has already
565 * created a route for the BSID. This in theory is impossible, but in
566 * practise we could see it. Assert it and scream if needed */
568 .fp_proto = FIB_PROTOCOL_IP6,
575 /* Lookup the FIB index associated to the table selected */
576 u32 fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6,
578 (u32) ~ 0 ? fib_table : 0));
582 /* Lookup whether there exists an entry for the BSID */
583 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
584 if (FIB_NODE_INDEX_INVALID != fei)
585 return -12; //There is an entry for such lookup
587 /* Add an SR policy object */
588 pool_get (sm->sr_policies, sr_policy);
589 memset (sr_policy, 0, sizeof (*sr_policy));
590 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
591 sr_policy->type = behavior;
592 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
593 sr_policy->is_encap = is_encap;
596 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
599 /* Create a segment list and add the index to the SR policy */
600 create_sl (sr_policy, segments, weight, is_encap);
602 /* If FIB doesnt exist, create them */
603 if (sm->fib_table_ip6 == (u32) ~ 0)
605 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
606 "SRv6 steering of IP6 prefixes through BSIDs");
607 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
608 "SRv6 steering of IP4 prefixes through BSIDs");
609 fib_table_flush (sm->fib_table_ip6, FIB_PROTOCOL_IP6,
611 fib_table_flush (sm->fib_table_ip4, FIB_PROTOCOL_IP6,
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_id_find_fib_index
666 (FIB_PROTOCOL_IP6, 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 vec_free (segment_list->rewrite_bsid);
688 pool_put_index (sm->sid_lists, *sl_index);
691 /* Remove SR policy entry */
692 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
693 pool_put (sm->sr_policies, sr_policy);
695 /* If FIB empty unlock it */
696 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
698 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6);
699 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6);
700 sm->fib_table_ip6 = (u32) ~ 0;
701 sm->fib_table_ip4 = (u32) ~ 0;
708 * @brief Modify an existing SR policy
710 * The possible modifications are adding a new Segment List, modifying an
711 * existing Segment List (modify the weight only) and delete a given
712 * Segment List from the SR Policy.
714 * @param bsid is the bindingSID of the SR Policy
715 * @param index is the index of the SR policy
716 * @param fib_table is the VRF where to install the FIB entry for the BSID
717 * @param operation is the operation to perform (among the top ones)
718 * @param segments is a vector of IPv6 address composing the segment list
719 * @param sl_index is the index of the Segment List to modify/delete
720 * @param weight is the weight of the sid list. optional.
721 * @param is_encap Mode. Encapsulation or SRH insertion.
723 * @return 0 if correct, else error
726 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
727 u8 operation, ip6_address_t * segments, u32 sl_index,
730 ip6_sr_main_t *sm = &sr_main;
731 ip6_sr_policy_t *sr_policy = 0;
732 ip6_sr_sl_t *segment_list;
733 u32 *sl_index_iterate;
738 p = mhash_get (&sm->sr_policies_index_hash, bsid);
740 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
746 sr_policy = pool_elt_at_index (sm->sr_policies, index);
751 if (operation == 1) /* Add SR List to an existing SR policy */
753 /* Create the new SL */
755 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
757 /* Create a new LB DPO */
758 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
759 update_lb (sr_policy);
760 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
761 update_replicate (sr_policy);
763 else if (operation == 2) /* Delete SR List from an existing SR policy */
765 /* Check that currently there are more than one SID list */
766 if (vec_len (sr_policy->segments_lists) == 1)
769 /* Check that the SR list does exist and is assigned to the sr policy */
770 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
771 if (*sl_index_iterate == sl_index)
774 if (*sl_index_iterate != sl_index)
777 /* Remove the lucky SR list that is being kicked out */
778 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
779 vec_free (segment_list->segments);
780 vec_free (segment_list->rewrite);
781 vec_free (segment_list->rewrite_bsid);
782 pool_put_index (sm->sid_lists, sl_index);
783 vec_del1 (sr_policy->segments_lists,
784 sl_index_iterate - sr_policy->segments_lists);
786 /* Create a new LB DPO */
787 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
788 update_lb (sr_policy);
789 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
790 update_replicate (sr_policy);
792 else if (operation == 3) /* Modify the weight of an existing SR List */
794 /* Find the corresponding SL */
795 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
796 if (*sl_index_iterate == sl_index)
799 if (*sl_index_iterate != sl_index)
802 /* Change the weight */
803 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
804 segment_list->weight = weight;
807 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
808 update_lb (sr_policy);
810 else /* Incorrect op. */
817 * @brief CLI for 'sr policies' command family
819 static clib_error_t *
820 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
821 vlib_cli_command_t * cmd)
824 char is_del = 0, is_add = 0, is_mod = 0;
826 ip6_address_t bsid, next_address;
827 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
828 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
829 ip6_address_t *segments = 0, *this_seg;
834 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
836 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
838 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
840 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
843 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
845 else if (!is_add && !policy_set
846 && unformat (input, "index %d", &sr_policy_index))
848 else if (unformat (input, "weight %d", &weight));
850 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
852 vec_add2 (segments, this_seg, 1);
853 clib_memcpy (this_seg->as_u8, next_address.as_u8,
856 else if (unformat (input, "add sl"))
858 else if (unformat (input, "del sl index %d", &sl_index))
860 else if (unformat (input, "mod sl index %d", &sl_index))
862 else if (fib_table == (u32) ~ 0
863 && unformat (input, "fib-table %d", &fib_table));
864 else if (unformat (input, "encap"))
866 else if (unformat (input, "insert"))
868 else if (unformat (input, "spray"))
874 if (!is_add && !is_mod && !is_del)
875 return clib_error_return (0, "Incorrect CLI");
878 return clib_error_return (0, "No SR policy BSID or index specified");
882 if (vec_len (segments) == 0)
883 return clib_error_return (0, "No Segment List specified");
884 rv = sr_policy_add (&bsid, segments, weight,
885 (is_spray ? SR_POLICY_TYPE_SPRAY :
886 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
889 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
894 return clib_error_return (0, "No SL modification specified");
895 if (operation != 1 && sl_index == (u32) ~ 0)
896 return clib_error_return (0, "No Segment List index specified");
897 if (operation == 1 && vec_len (segments) == 0)
898 return clib_error_return (0, "No Segment List specified");
899 if (operation == 3 && weight == (u32) ~ 0)
900 return clib_error_return (0, "No new weight for the SL specified");
901 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
902 sr_policy_index, fib_table, operation, segments,
913 return clib_error_return (0,
914 "There is already a FIB entry for the BindingSID address.\n"
915 "The SR policy could not be created.");
917 return clib_error_return (0, "The specified FIB table does not exist.");
919 return clib_error_return (0,
920 "The selected SR policy only contains ONE segment list. "
921 "Please remove the SR policy instead");
923 return clib_error_return (0,
924 "Could not delete the segment list. "
925 "It is not associated with that SR policy.");
927 return clib_error_return (0,
928 "Could not modify the segment list. "
929 "The given SL is not associated with such SR policy.");
931 return clib_error_return (0, "BUG: sr policy returns %d", rv);
937 VLIB_CLI_COMMAND (sr_policy_command, static) = {
939 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
940 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
942 "Manipulation of SR policies.\n"
943 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
944 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
945 "Segment Routing policies might be of type encapsulation or srh insertion\n"
946 "Each SR policy will be associated with a unique BindingSID.\n"
947 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
948 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
949 "The add command will create a SR policy with its first segment list (sl)\n"
950 "The mod command allows you to add, remove, or modify the existing segment lists\n"
951 "within an SR policy.\n"
952 "The del command allows you to delete a SR policy along with all its associated\n"
954 .function = sr_policy_command_fn,
959 * @brief CLI to display onscreen all the SR policies
961 static clib_error_t *
962 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
963 vlib_cli_command_t * cmd)
965 ip6_sr_main_t *sm = &sr_main;
967 ip6_sr_sl_t *segment_list = 0;
968 ip6_sr_policy_t *sr_policy = 0;
969 ip6_sr_policy_t **vec_policies = 0;
974 vlib_cli_output (vm, "SR policies:");
977 pool_foreach (sr_policy, sm->sr_policies,
978 {vec_add1 (vec_policies, sr_policy); } );
981 vec_foreach_index (i, vec_policies)
983 sr_policy = vec_policies[i];
984 vlib_cli_output (vm, "[%u].-\tBSID: %U",
985 (u32) (sr_policy - sm->sr_policies),
986 format_ip6_address, &sr_policy->bsid);
987 vlib_cli_output (vm, "\tBehavior: %s",
988 (sr_policy->is_encap ? "Encapsulation" :
990 vlib_cli_output (vm, "\tType: %s",
992 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
993 vlib_cli_output (vm, "\tFIB table: %u",
994 (sr_policy->fib_table !=
995 (u32) ~ 0 ? sr_policy->fib_table : 0));
996 vlib_cli_output (vm, "\tSegment Lists:");
997 vec_foreach (sl_index, sr_policy->segments_lists)
1000 s = format (s, "\t[%u].- ", *sl_index);
1001 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1002 s = format (s, "< ");
1003 vec_foreach (addr, segment_list->segments)
1005 s = format (s, "%U, ", format_ip6_address, addr);
1007 s = format (s, "\b\b > ");
1008 s = format (s, "weight: %u", segment_list->weight);
1009 vlib_cli_output (vm, " %s", s);
1011 vlib_cli_output (vm, "-----------");
1017 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1018 .path = "show sr policies",
1019 .short_help = "show sr policies",
1020 .function = show_sr_policies_command_fn,
1024 /*************************** SR rewrite graph node ****************************/
1026 * @brief Trace for the SR Policy Rewrite graph node
1029 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1032 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1033 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1034 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1037 (s, "SR-policy-rewrite: src %U dst %U",
1038 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1044 * @brief IPv6 encapsulation processing as per RFC2473
1046 static_always_inline void
1047 encaps_processing_v6 (vlib_node_runtime_t * node,
1049 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1053 ip0_encap->hop_limit -= 1;
1055 ip0->payload_length + sizeof (ip6_header_t) +
1056 clib_net_to_host_u16 (ip0_encap->payload_length);
1057 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1058 ip0->ip_version_traffic_class_and_flow_label =
1059 ip0_encap->ip_version_traffic_class_and_flow_label;
1063 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1066 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1067 vlib_frame_t * from_frame)
1069 ip6_sr_main_t *sm = &sr_main;
1070 u32 n_left_from, next_index, *from, *to_next;
1072 from = vlib_frame_vector_args (from_frame);
1073 n_left_from = from_frame->n_vectors;
1075 next_index = node->cached_next_index;
1077 int encap_pkts = 0, bsid_pkts = 0;
1079 while (n_left_from > 0)
1083 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1086 while (n_left_from >= 8 && n_left_to_next >= 4)
1088 u32 bi0, bi1, bi2, bi3;
1089 vlib_buffer_t *b0, *b1, *b2, *b3;
1090 u32 next0, next1, next2, next3;
1091 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1092 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1093 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1094 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1096 /* Prefetch next iteration. */
1098 vlib_buffer_t *p4, *p5, *p6, *p7;
1100 p4 = vlib_get_buffer (vm, from[4]);
1101 p5 = vlib_get_buffer (vm, from[5]);
1102 p6 = vlib_get_buffer (vm, from[6]);
1103 p7 = vlib_get_buffer (vm, from[7]);
1105 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1106 vlib_prefetch_buffer_header (p4, LOAD);
1107 vlib_prefetch_buffer_header (p5, LOAD);
1108 vlib_prefetch_buffer_header (p6, LOAD);
1109 vlib_prefetch_buffer_header (p7, LOAD);
1111 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1112 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1113 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1114 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1117 to_next[0] = bi0 = from[0];
1118 to_next[1] = bi1 = from[1];
1119 to_next[2] = bi2 = from[2];
1120 to_next[3] = bi3 = from[3];
1124 n_left_to_next -= 4;
1126 b0 = vlib_get_buffer (vm, bi0);
1127 b1 = vlib_get_buffer (vm, bi1);
1128 b2 = vlib_get_buffer (vm, bi2);
1129 b3 = vlib_get_buffer (vm, bi3);
1132 pool_elt_at_index (sm->sid_lists,
1133 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1135 pool_elt_at_index (sm->sid_lists,
1136 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1138 pool_elt_at_index (sm->sid_lists,
1139 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1141 pool_elt_at_index (sm->sid_lists,
1142 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1144 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1145 vec_len (sl0->rewrite));
1146 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1147 vec_len (sl1->rewrite));
1148 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1149 vec_len (sl2->rewrite));
1150 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1151 vec_len (sl3->rewrite));
1153 ip0_encap = vlib_buffer_get_current (b0);
1154 ip1_encap = vlib_buffer_get_current (b1);
1155 ip2_encap = vlib_buffer_get_current (b2);
1156 ip3_encap = vlib_buffer_get_current (b3);
1158 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1159 sl0->rewrite, vec_len (sl0->rewrite));
1160 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1161 sl1->rewrite, vec_len (sl1->rewrite));
1162 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1163 sl2->rewrite, vec_len (sl2->rewrite));
1164 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1165 sl3->rewrite, vec_len (sl3->rewrite));
1167 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1168 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1169 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1170 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1172 ip0 = vlib_buffer_get_current (b0);
1173 ip1 = vlib_buffer_get_current (b1);
1174 ip2 = vlib_buffer_get_current (b2);
1175 ip3 = vlib_buffer_get_current (b3);
1177 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1178 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1179 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1180 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1182 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1184 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1186 sr_policy_rewrite_trace_t *tr =
1187 vlib_add_trace (vm, node, b0, sizeof (*tr));
1188 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1189 sizeof (tr->src.as_u8));
1190 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1191 sizeof (tr->dst.as_u8));
1194 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1196 sr_policy_rewrite_trace_t *tr =
1197 vlib_add_trace (vm, node, b1, sizeof (*tr));
1198 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1199 sizeof (tr->src.as_u8));
1200 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1201 sizeof (tr->dst.as_u8));
1204 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1206 sr_policy_rewrite_trace_t *tr =
1207 vlib_add_trace (vm, node, b2, sizeof (*tr));
1208 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1209 sizeof (tr->src.as_u8));
1210 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1211 sizeof (tr->dst.as_u8));
1214 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1216 sr_policy_rewrite_trace_t *tr =
1217 vlib_add_trace (vm, node, b3, sizeof (*tr));
1218 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1219 sizeof (tr->src.as_u8));
1220 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1221 sizeof (tr->dst.as_u8));
1226 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1227 n_left_to_next, bi0, bi1, bi2, bi3,
1228 next0, next1, next2, next3);
1231 /* Single loop for potentially the last three packets */
1232 while (n_left_from > 0 && n_left_to_next > 0)
1236 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1238 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1245 n_left_to_next -= 1;
1246 b0 = vlib_get_buffer (vm, bi0);
1249 pool_elt_at_index (sm->sid_lists,
1250 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1251 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1252 vec_len (sl0->rewrite));
1254 ip0_encap = vlib_buffer_get_current (b0);
1256 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1257 sl0->rewrite, vec_len (sl0->rewrite));
1258 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1260 ip0 = vlib_buffer_get_current (b0);
1262 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1264 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1265 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1267 sr_policy_rewrite_trace_t *tr =
1268 vlib_add_trace (vm, node, b0, sizeof (*tr));
1269 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1270 sizeof (tr->src.as_u8));
1271 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1272 sizeof (tr->dst.as_u8));
1276 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1277 n_left_to_next, bi0, next0);
1280 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1283 /* Update counters */
1284 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1285 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1287 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1288 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1291 return from_frame->n_vectors;
1295 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1296 .function = sr_policy_rewrite_encaps,
1297 .name = "sr-pl-rewrite-encaps",
1298 .vector_size = sizeof (u32),
1299 .format_trace = format_sr_policy_rewrite_trace,
1300 .type = VLIB_NODE_TYPE_INTERNAL,
1301 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1302 .error_strings = sr_policy_rewrite_error_strings,
1303 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1305 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1306 foreach_sr_policy_rewrite_next
1313 * @brief IPv4 encapsulation processing as per RFC2473
1315 static_always_inline void
1316 encaps_processing_v4 (vlib_node_runtime_t * node,
1318 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1321 ip6_sr_header_t *sr0;
1325 /* Inner IPv4: Decrement TTL & update checksum */
1326 ip0_encap->ttl -= 1;
1327 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1328 checksum0 += checksum0 >= 0xffff;
1329 ip0_encap->checksum = checksum0;
1331 /* Outer IPv6: Update length, FL, proto */
1332 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1333 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1334 ip0->ip_version_traffic_class_and_flow_label =
1335 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1336 ((ip0_encap->tos & 0xFF) << 20));
1337 sr0 = (void *) (ip0 + 1);
1338 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1342 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1345 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1346 vlib_frame_t * from_frame)
1348 ip6_sr_main_t *sm = &sr_main;
1349 u32 n_left_from, next_index, *from, *to_next;
1351 from = vlib_frame_vector_args (from_frame);
1352 n_left_from = from_frame->n_vectors;
1354 next_index = node->cached_next_index;
1356 int encap_pkts = 0, bsid_pkts = 0;
1358 while (n_left_from > 0)
1362 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1365 while (n_left_from >= 8 && n_left_to_next >= 4)
1367 u32 bi0, bi1, bi2, bi3;
1368 vlib_buffer_t *b0, *b1, *b2, *b3;
1369 u32 next0, next1, next2, next3;
1370 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1371 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1372 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1373 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1375 /* Prefetch next iteration. */
1377 vlib_buffer_t *p4, *p5, *p6, *p7;
1379 p4 = vlib_get_buffer (vm, from[4]);
1380 p5 = vlib_get_buffer (vm, from[5]);
1381 p6 = vlib_get_buffer (vm, from[6]);
1382 p7 = vlib_get_buffer (vm, from[7]);
1384 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1385 vlib_prefetch_buffer_header (p4, LOAD);
1386 vlib_prefetch_buffer_header (p5, LOAD);
1387 vlib_prefetch_buffer_header (p6, LOAD);
1388 vlib_prefetch_buffer_header (p7, LOAD);
1390 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1391 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1392 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1393 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1396 to_next[0] = bi0 = from[0];
1397 to_next[1] = bi1 = from[1];
1398 to_next[2] = bi2 = from[2];
1399 to_next[3] = bi3 = from[3];
1403 n_left_to_next -= 4;
1405 b0 = vlib_get_buffer (vm, bi0);
1406 b1 = vlib_get_buffer (vm, bi1);
1407 b2 = vlib_get_buffer (vm, bi2);
1408 b3 = vlib_get_buffer (vm, bi3);
1411 pool_elt_at_index (sm->sid_lists,
1412 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1414 pool_elt_at_index (sm->sid_lists,
1415 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1417 pool_elt_at_index (sm->sid_lists,
1418 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1420 pool_elt_at_index (sm->sid_lists,
1421 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1422 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1423 vec_len (sl0->rewrite));
1424 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1425 vec_len (sl1->rewrite));
1426 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1427 vec_len (sl2->rewrite));
1428 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1429 vec_len (sl3->rewrite));
1431 ip0_encap = vlib_buffer_get_current (b0);
1432 ip1_encap = vlib_buffer_get_current (b1);
1433 ip2_encap = vlib_buffer_get_current (b2);
1434 ip3_encap = vlib_buffer_get_current (b3);
1436 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1437 sl0->rewrite, vec_len (sl0->rewrite));
1438 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1439 sl1->rewrite, vec_len (sl1->rewrite));
1440 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1441 sl2->rewrite, vec_len (sl2->rewrite));
1442 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1443 sl3->rewrite, vec_len (sl3->rewrite));
1445 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1446 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1447 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1448 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1450 ip0 = vlib_buffer_get_current (b0);
1451 ip1 = vlib_buffer_get_current (b1);
1452 ip2 = vlib_buffer_get_current (b2);
1453 ip3 = vlib_buffer_get_current (b3);
1455 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1456 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1457 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1458 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1460 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1462 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1464 sr_policy_rewrite_trace_t *tr =
1465 vlib_add_trace (vm, node, b0, sizeof (*tr));
1466 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1467 sizeof (tr->src.as_u8));
1468 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1469 sizeof (tr->dst.as_u8));
1472 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b1, sizeof (*tr));
1476 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
1482 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1484 sr_policy_rewrite_trace_t *tr =
1485 vlib_add_trace (vm, node, b2, sizeof (*tr));
1486 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1487 sizeof (tr->src.as_u8));
1488 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1489 sizeof (tr->dst.as_u8));
1492 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1494 sr_policy_rewrite_trace_t *tr =
1495 vlib_add_trace (vm, node, b3, sizeof (*tr));
1496 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1497 sizeof (tr->src.as_u8));
1498 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1499 sizeof (tr->dst.as_u8));
1504 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1505 n_left_to_next, bi0, bi1, bi2, bi3,
1506 next0, next1, next2, next3);
1509 /* Single loop for potentially the last three packets */
1510 while (n_left_from > 0 && n_left_to_next > 0)
1514 ip6_header_t *ip0 = 0;
1515 ip4_header_t *ip0_encap = 0;
1517 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1524 n_left_to_next -= 1;
1525 b0 = vlib_get_buffer (vm, bi0);
1528 pool_elt_at_index (sm->sid_lists,
1529 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1530 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1531 vec_len (sl0->rewrite));
1533 ip0_encap = vlib_buffer_get_current (b0);
1535 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1536 sl0->rewrite, vec_len (sl0->rewrite));
1537 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1539 ip0 = vlib_buffer_get_current (b0);
1541 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1543 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1544 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1546 sr_policy_rewrite_trace_t *tr =
1547 vlib_add_trace (vm, node, b0, sizeof (*tr));
1548 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1549 sizeof (tr->src.as_u8));
1550 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1551 sizeof (tr->dst.as_u8));
1555 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1556 n_left_to_next, bi0, next0);
1559 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1562 /* Update counters */
1563 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1564 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1566 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1567 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1570 return from_frame->n_vectors;
1574 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1575 .function = sr_policy_rewrite_encaps_v4,
1576 .name = "sr-pl-rewrite-encaps-v4",
1577 .vector_size = sizeof (u32),
1578 .format_trace = format_sr_policy_rewrite_trace,
1579 .type = VLIB_NODE_TYPE_INTERNAL,
1580 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1581 .error_strings = sr_policy_rewrite_error_strings,
1582 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1584 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1585 foreach_sr_policy_rewrite_next
1592 ip_flow_hash (void *data)
1594 ip4_header_t *iph = (ip4_header_t *) data;
1596 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1597 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1599 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1605 return (*((u64 *) m) & 0xffffffffffff);
1609 l2_flow_hash (vlib_buffer_t * b0)
1611 ethernet_header_t *eh;
1613 uword is_ip, eh_size;
1616 eh = vlib_buffer_get_current (b0);
1617 eh_type = clib_net_to_host_u16 (eh->type);
1618 eh_size = ethernet_buffer_header_size (b0);
1620 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1622 /* since we have 2 cache lines, use them */
1624 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1628 b = mac_to_u64 ((u8 *) eh->dst_address);
1629 c = mac_to_u64 ((u8 *) eh->src_address);
1630 hash_mix64 (a, b, c);
1636 * @brief Graph node for applying a SR policy into a L2 frame
1639 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1640 vlib_frame_t * from_frame)
1642 ip6_sr_main_t *sm = &sr_main;
1643 u32 n_left_from, next_index, *from, *to_next;
1645 from = vlib_frame_vector_args (from_frame);
1646 n_left_from = from_frame->n_vectors;
1648 next_index = node->cached_next_index;
1650 int encap_pkts = 0, bsid_pkts = 0;
1652 while (n_left_from > 0)
1656 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1659 while (n_left_from >= 8 && n_left_to_next >= 4)
1661 u32 bi0, bi1, bi2, bi3;
1662 vlib_buffer_t *b0, *b1, *b2, *b3;
1663 u32 next0, next1, next2, next3;
1664 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1665 ethernet_header_t *en0, *en1, *en2, *en3;
1666 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1667 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1668 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1669 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1671 /* Prefetch next iteration. */
1673 vlib_buffer_t *p4, *p5, *p6, *p7;
1675 p4 = vlib_get_buffer (vm, from[4]);
1676 p5 = vlib_get_buffer (vm, from[5]);
1677 p6 = vlib_get_buffer (vm, from[6]);
1678 p7 = vlib_get_buffer (vm, from[7]);
1680 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1681 vlib_prefetch_buffer_header (p4, LOAD);
1682 vlib_prefetch_buffer_header (p5, LOAD);
1683 vlib_prefetch_buffer_header (p6, LOAD);
1684 vlib_prefetch_buffer_header (p7, LOAD);
1686 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1687 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1688 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1689 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1692 to_next[0] = bi0 = from[0];
1693 to_next[1] = bi1 = from[1];
1694 to_next[2] = bi2 = from[2];
1695 to_next[3] = bi3 = from[3];
1699 n_left_to_next -= 4;
1701 b0 = vlib_get_buffer (vm, bi0);
1702 b1 = vlib_get_buffer (vm, bi1);
1703 b2 = vlib_get_buffer (vm, bi2);
1704 b3 = vlib_get_buffer (vm, bi3);
1706 sp0 = pool_elt_at_index (sm->sr_policies,
1707 sm->sw_iface_sr_policies[vnet_buffer
1711 sp1 = pool_elt_at_index (sm->sr_policies,
1712 sm->sw_iface_sr_policies[vnet_buffer
1716 sp2 = pool_elt_at_index (sm->sr_policies,
1717 sm->sw_iface_sr_policies[vnet_buffer
1721 sp3 = pool_elt_at_index (sm->sr_policies,
1722 sm->sw_iface_sr_policies[vnet_buffer
1726 if (vec_len (sp0->segments_lists) == 1)
1727 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1730 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1731 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1732 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1733 (vec_len (sp0->segments_lists) - 1))];
1736 if (vec_len (sp1->segments_lists) == 1)
1737 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1740 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1741 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1742 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1743 (vec_len (sp1->segments_lists) - 1))];
1746 if (vec_len (sp2->segments_lists) == 1)
1747 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1750 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1751 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1752 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1753 (vec_len (sp2->segments_lists) - 1))];
1756 if (vec_len (sp3->segments_lists) == 1)
1757 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1760 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1761 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1762 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1763 (vec_len (sp3->segments_lists) - 1))];
1767 pool_elt_at_index (sm->sid_lists,
1768 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1770 pool_elt_at_index (sm->sid_lists,
1771 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1773 pool_elt_at_index (sm->sid_lists,
1774 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1776 pool_elt_at_index (sm->sid_lists,
1777 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1779 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1780 vec_len (sl0->rewrite));
1781 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1782 vec_len (sl1->rewrite));
1783 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1784 vec_len (sl2->rewrite));
1785 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1786 vec_len (sl3->rewrite));
1788 en0 = vlib_buffer_get_current (b0);
1789 en1 = vlib_buffer_get_current (b1);
1790 en2 = vlib_buffer_get_current (b2);
1791 en3 = vlib_buffer_get_current (b3);
1793 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1794 vec_len (sl0->rewrite));
1795 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1796 vec_len (sl1->rewrite));
1797 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1798 vec_len (sl2->rewrite));
1799 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1800 vec_len (sl3->rewrite));
1802 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1803 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1804 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1805 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1807 ip0 = vlib_buffer_get_current (b0);
1808 ip1 = vlib_buffer_get_current (b1);
1809 ip2 = vlib_buffer_get_current (b2);
1810 ip3 = vlib_buffer_get_current (b3);
1812 ip0->payload_length =
1813 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1814 ip1->payload_length =
1815 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1816 ip2->payload_length =
1817 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1818 ip3->payload_length =
1819 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1821 sr0 = (void *) (ip0 + 1);
1822 sr1 = (void *) (ip1 + 1);
1823 sr2 = (void *) (ip2 + 1);
1824 sr3 = (void *) (ip3 + 1);
1826 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1827 IP_PROTOCOL_IP6_NONXT;
1829 /* Which Traffic class and flow label do I set ? */
1830 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1832 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1834 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1836 sr_policy_rewrite_trace_t *tr =
1837 vlib_add_trace (vm, node, b0, sizeof (*tr));
1838 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1839 sizeof (tr->src.as_u8));
1840 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1841 sizeof (tr->dst.as_u8));
1844 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1846 sr_policy_rewrite_trace_t *tr =
1847 vlib_add_trace (vm, node, b1, sizeof (*tr));
1848 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1849 sizeof (tr->src.as_u8));
1850 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1851 sizeof (tr->dst.as_u8));
1854 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1856 sr_policy_rewrite_trace_t *tr =
1857 vlib_add_trace (vm, node, b2, sizeof (*tr));
1858 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1859 sizeof (tr->src.as_u8));
1860 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1861 sizeof (tr->dst.as_u8));
1864 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1866 sr_policy_rewrite_trace_t *tr =
1867 vlib_add_trace (vm, node, b3, sizeof (*tr));
1868 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1869 sizeof (tr->src.as_u8));
1870 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1871 sizeof (tr->dst.as_u8));
1876 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1877 n_left_to_next, bi0, bi1, bi2, bi3,
1878 next0, next1, next2, next3);
1881 /* Single loop for potentially the last three packets */
1882 while (n_left_from > 0 && n_left_to_next > 0)
1886 ip6_header_t *ip0 = 0;
1887 ip6_sr_header_t *sr0;
1888 ethernet_header_t *en0;
1889 ip6_sr_policy_t *sp0;
1891 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1898 n_left_to_next -= 1;
1899 b0 = vlib_get_buffer (vm, bi0);
1901 /* Find the SR policy */
1902 sp0 = pool_elt_at_index (sm->sr_policies,
1903 sm->sw_iface_sr_policies[vnet_buffer
1907 /* In case there is more than one SL, LB among them */
1908 if (vec_len (sp0->segments_lists) == 1)
1909 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1912 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1913 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1914 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1915 (vec_len (sp0->segments_lists) - 1))];
1918 pool_elt_at_index (sm->sid_lists,
1919 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1920 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1921 vec_len (sl0->rewrite));
1923 en0 = vlib_buffer_get_current (b0);
1925 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1926 vec_len (sl0->rewrite));
1928 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1930 ip0 = vlib_buffer_get_current (b0);
1932 ip0->payload_length =
1933 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1935 sr0 = (void *) (ip0 + 1);
1936 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1938 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1939 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1941 sr_policy_rewrite_trace_t *tr =
1942 vlib_add_trace (vm, node, b0, sizeof (*tr));
1943 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1944 sizeof (tr->src.as_u8));
1945 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1946 sizeof (tr->dst.as_u8));
1950 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1951 n_left_to_next, bi0, next0);
1954 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1957 /* Update counters */
1958 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1959 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1961 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1962 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1965 return from_frame->n_vectors;
1969 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1970 .function = sr_policy_rewrite_encaps_l2,
1971 .name = "sr-pl-rewrite-encaps-l2",
1972 .vector_size = sizeof (u32),
1973 .format_trace = format_sr_policy_rewrite_trace,
1974 .type = VLIB_NODE_TYPE_INTERNAL,
1975 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1976 .error_strings = sr_policy_rewrite_error_strings,
1977 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1979 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1980 foreach_sr_policy_rewrite_next
1987 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1990 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1991 vlib_frame_t * from_frame)
1993 ip6_sr_main_t *sm = &sr_main;
1994 u32 n_left_from, next_index, *from, *to_next;
1996 from = vlib_frame_vector_args (from_frame);
1997 n_left_from = from_frame->n_vectors;
1999 next_index = node->cached_next_index;
2001 int insert_pkts = 0, bsid_pkts = 0;
2003 while (n_left_from > 0)
2007 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2010 while (n_left_from >= 8 && n_left_to_next >= 4)
2012 u32 bi0, bi1, bi2, bi3;
2013 vlib_buffer_t *b0, *b1, *b2, *b3;
2014 u32 next0, next1, next2, next3;
2015 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2016 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2017 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2018 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2019 u16 new_l0, new_l1, new_l2, new_l3;
2021 /* Prefetch next iteration. */
2023 vlib_buffer_t *p4, *p5, *p6, *p7;
2025 p4 = vlib_get_buffer (vm, from[4]);
2026 p5 = vlib_get_buffer (vm, from[5]);
2027 p6 = vlib_get_buffer (vm, from[6]);
2028 p7 = vlib_get_buffer (vm, from[7]);
2030 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2031 vlib_prefetch_buffer_header (p4, LOAD);
2032 vlib_prefetch_buffer_header (p5, LOAD);
2033 vlib_prefetch_buffer_header (p6, LOAD);
2034 vlib_prefetch_buffer_header (p7, LOAD);
2036 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2037 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2038 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2039 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2042 to_next[0] = bi0 = from[0];
2043 to_next[1] = bi1 = from[1];
2044 to_next[2] = bi2 = from[2];
2045 to_next[3] = bi3 = from[3];
2049 n_left_to_next -= 4;
2051 b0 = vlib_get_buffer (vm, bi0);
2052 b1 = vlib_get_buffer (vm, bi1);
2053 b2 = vlib_get_buffer (vm, bi2);
2054 b3 = vlib_get_buffer (vm, bi3);
2057 pool_elt_at_index (sm->sid_lists,
2058 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2060 pool_elt_at_index (sm->sid_lists,
2061 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2063 pool_elt_at_index (sm->sid_lists,
2064 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2066 pool_elt_at_index (sm->sid_lists,
2067 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2068 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2069 vec_len (sl0->rewrite));
2070 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2071 vec_len (sl1->rewrite));
2072 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2073 vec_len (sl2->rewrite));
2074 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2075 vec_len (sl3->rewrite));
2077 ip0 = vlib_buffer_get_current (b0);
2078 ip1 = vlib_buffer_get_current (b1);
2079 ip2 = vlib_buffer_get_current (b2);
2080 ip3 = vlib_buffer_get_current (b3);
2082 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2084 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2085 ip6_ext_header_len (ip0 + 1));
2087 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2089 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2091 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2092 ip6_ext_header_len (ip1 + 1));
2094 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2096 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2098 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2099 ip6_ext_header_len (ip2 + 1));
2101 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2103 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2105 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2106 ip6_ext_header_len (ip3 + 1));
2108 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2110 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2111 (void *) sr0 - (void *) ip0);
2112 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2113 (void *) sr1 - (void *) ip1);
2114 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2115 (void *) sr2 - (void *) ip2);
2116 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2117 (void *) sr3 - (void *) ip3);
2119 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2120 vec_len (sl0->rewrite));
2121 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2122 vec_len (sl1->rewrite));
2123 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2124 vec_len (sl2->rewrite));
2125 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2126 vec_len (sl3->rewrite));
2128 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2129 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2130 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2131 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2133 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2134 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2135 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2136 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2138 ip0->hop_limit -= 1;
2139 ip1->hop_limit -= 1;
2140 ip2->hop_limit -= 1;
2141 ip3->hop_limit -= 1;
2144 clib_net_to_host_u16 (ip0->payload_length) +
2145 vec_len (sl0->rewrite);
2147 clib_net_to_host_u16 (ip1->payload_length) +
2148 vec_len (sl1->rewrite);
2150 clib_net_to_host_u16 (ip2->payload_length) +
2151 vec_len (sl2->rewrite);
2153 clib_net_to_host_u16 (ip3->payload_length) +
2154 vec_len (sl3->rewrite);
2156 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2157 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2158 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2159 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2161 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2162 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2163 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2164 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2166 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2167 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2168 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2169 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2170 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2171 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2172 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2173 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2175 ip0->dst_address.as_u64[0] =
2176 (sr0->segments + sr0->segments_left)->as_u64[0];
2177 ip0->dst_address.as_u64[1] =
2178 (sr0->segments + sr0->segments_left)->as_u64[1];
2179 ip1->dst_address.as_u64[0] =
2180 (sr1->segments + sr1->segments_left)->as_u64[0];
2181 ip1->dst_address.as_u64[1] =
2182 (sr1->segments + sr1->segments_left)->as_u64[1];
2183 ip2->dst_address.as_u64[0] =
2184 (sr2->segments + sr2->segments_left)->as_u64[0];
2185 ip2->dst_address.as_u64[1] =
2186 (sr2->segments + sr2->segments_left)->as_u64[1];
2187 ip3->dst_address.as_u64[0] =
2188 (sr3->segments + sr3->segments_left)->as_u64[0];
2189 ip3->dst_address.as_u64[1] =
2190 (sr3->segments + sr3->segments_left)->as_u64[1];
2192 ip6_ext_header_t *ip_ext;
2193 if (ip0 + 1 == (void *) sr0)
2195 sr0->protocol = ip0->protocol;
2196 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2200 ip_ext = (void *) (ip0 + 1);
2201 sr0->protocol = ip_ext->next_hdr;
2202 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2205 if (ip1 + 1 == (void *) sr1)
2207 sr1->protocol = ip1->protocol;
2208 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2212 ip_ext = (void *) (ip2 + 1);
2213 sr2->protocol = ip_ext->next_hdr;
2214 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2217 if (ip2 + 1 == (void *) sr2)
2219 sr2->protocol = ip2->protocol;
2220 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2224 ip_ext = (void *) (ip2 + 1);
2225 sr2->protocol = ip_ext->next_hdr;
2226 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2229 if (ip3 + 1 == (void *) sr3)
2231 sr3->protocol = ip3->protocol;
2232 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2236 ip_ext = (void *) (ip3 + 1);
2237 sr3->protocol = ip_ext->next_hdr;
2238 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2243 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2245 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2247 sr_policy_rewrite_trace_t *tr =
2248 vlib_add_trace (vm, node, b0, sizeof (*tr));
2249 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2250 sizeof (tr->src.as_u8));
2251 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2252 sizeof (tr->dst.as_u8));
2255 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2257 sr_policy_rewrite_trace_t *tr =
2258 vlib_add_trace (vm, node, b1, sizeof (*tr));
2259 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2260 sizeof (tr->src.as_u8));
2261 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2262 sizeof (tr->dst.as_u8));
2265 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2267 sr_policy_rewrite_trace_t *tr =
2268 vlib_add_trace (vm, node, b2, sizeof (*tr));
2269 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2270 sizeof (tr->src.as_u8));
2271 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2272 sizeof (tr->dst.as_u8));
2275 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2277 sr_policy_rewrite_trace_t *tr =
2278 vlib_add_trace (vm, node, b3, sizeof (*tr));
2279 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2280 sizeof (tr->src.as_u8));
2281 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2282 sizeof (tr->dst.as_u8));
2286 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2287 n_left_to_next, bi0, bi1, bi2, bi3,
2288 next0, next1, next2, next3);
2291 /* Single loop for potentially the last three packets */
2292 while (n_left_from > 0 && n_left_to_next > 0)
2296 ip6_header_t *ip0 = 0;
2297 ip6_sr_header_t *sr0 = 0;
2299 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2307 n_left_to_next -= 1;
2309 b0 = vlib_get_buffer (vm, bi0);
2311 pool_elt_at_index (sm->sid_lists,
2312 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2313 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2314 vec_len (sl0->rewrite));
2316 ip0 = vlib_buffer_get_current (b0);
2318 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2320 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2321 ip6_ext_header_len (ip0 + 1));
2323 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2325 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2326 (void *) sr0 - (void *) ip0);
2327 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2328 vec_len (sl0->rewrite));
2330 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2332 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2333 ip0->hop_limit -= 1;
2335 clib_net_to_host_u16 (ip0->payload_length) +
2336 vec_len (sl0->rewrite);
2337 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2339 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2340 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2341 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2343 ip0->dst_address.as_u64[0] =
2344 (sr0->segments + sr0->segments_left)->as_u64[0];
2345 ip0->dst_address.as_u64[1] =
2346 (sr0->segments + sr0->segments_left)->as_u64[1];
2348 if (ip0 + 1 == (void *) sr0)
2350 sr0->protocol = ip0->protocol;
2351 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2355 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2356 sr0->protocol = ip_ext->next_hdr;
2357 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2360 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2361 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2363 sr_policy_rewrite_trace_t *tr =
2364 vlib_add_trace (vm, node, b0, sizeof (*tr));
2365 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2366 sizeof (tr->src.as_u8));
2367 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2368 sizeof (tr->dst.as_u8));
2373 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2374 n_left_to_next, bi0, next0);
2377 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2380 /* Update counters */
2381 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2382 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2384 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2385 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2387 return from_frame->n_vectors;
2391 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2392 .function = sr_policy_rewrite_insert,
2393 .name = "sr-pl-rewrite-insert",
2394 .vector_size = sizeof (u32),
2395 .format_trace = format_sr_policy_rewrite_trace,
2396 .type = VLIB_NODE_TYPE_INTERNAL,
2397 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2398 .error_strings = sr_policy_rewrite_error_strings,
2399 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2401 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2402 foreach_sr_policy_rewrite_next
2409 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2412 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2413 vlib_frame_t * from_frame)
2415 ip6_sr_main_t *sm = &sr_main;
2416 u32 n_left_from, next_index, *from, *to_next;
2418 from = vlib_frame_vector_args (from_frame);
2419 n_left_from = from_frame->n_vectors;
2421 next_index = node->cached_next_index;
2423 int insert_pkts = 0, bsid_pkts = 0;
2425 while (n_left_from > 0)
2429 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2432 while (n_left_from >= 8 && n_left_to_next >= 4)
2434 u32 bi0, bi1, bi2, bi3;
2435 vlib_buffer_t *b0, *b1, *b2, *b3;
2436 u32 next0, next1, next2, next3;
2437 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2438 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2439 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2440 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2441 u16 new_l0, new_l1, new_l2, new_l3;
2443 /* Prefetch next iteration. */
2445 vlib_buffer_t *p4, *p5, *p6, *p7;
2447 p4 = vlib_get_buffer (vm, from[4]);
2448 p5 = vlib_get_buffer (vm, from[5]);
2449 p6 = vlib_get_buffer (vm, from[6]);
2450 p7 = vlib_get_buffer (vm, from[7]);
2452 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2453 vlib_prefetch_buffer_header (p4, LOAD);
2454 vlib_prefetch_buffer_header (p5, LOAD);
2455 vlib_prefetch_buffer_header (p6, LOAD);
2456 vlib_prefetch_buffer_header (p7, LOAD);
2458 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2459 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2460 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2461 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2464 to_next[0] = bi0 = from[0];
2465 to_next[1] = bi1 = from[1];
2466 to_next[2] = bi2 = from[2];
2467 to_next[3] = bi3 = from[3];
2471 n_left_to_next -= 4;
2473 b0 = vlib_get_buffer (vm, bi0);
2474 b1 = vlib_get_buffer (vm, bi1);
2475 b2 = vlib_get_buffer (vm, bi2);
2476 b3 = vlib_get_buffer (vm, bi3);
2479 pool_elt_at_index (sm->sid_lists,
2480 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2482 pool_elt_at_index (sm->sid_lists,
2483 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2485 pool_elt_at_index (sm->sid_lists,
2486 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2488 pool_elt_at_index (sm->sid_lists,
2489 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2490 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2491 vec_len (sl0->rewrite_bsid));
2492 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2493 vec_len (sl1->rewrite_bsid));
2494 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2495 vec_len (sl2->rewrite_bsid));
2496 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2497 vec_len (sl3->rewrite_bsid));
2499 ip0 = vlib_buffer_get_current (b0);
2500 ip1 = vlib_buffer_get_current (b1);
2501 ip2 = vlib_buffer_get_current (b2);
2502 ip3 = vlib_buffer_get_current (b3);
2504 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2506 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2507 ip6_ext_header_len (ip0 + 1));
2509 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2511 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2513 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2514 ip6_ext_header_len (ip1 + 1));
2516 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2518 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2520 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2521 ip6_ext_header_len (ip2 + 1));
2523 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2525 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2527 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2528 ip6_ext_header_len (ip3 + 1));
2530 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2532 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2533 (void *) sr0 - (void *) ip0);
2534 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2535 (void *) sr1 - (void *) ip1);
2536 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2537 (void *) sr2 - (void *) ip2);
2538 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2539 (void *) sr3 - (void *) ip3);
2541 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2542 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2543 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2544 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2545 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2546 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2547 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2548 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2550 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2551 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2552 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2553 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2555 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2556 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2557 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2558 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2560 ip0->hop_limit -= 1;
2561 ip1->hop_limit -= 1;
2562 ip2->hop_limit -= 1;
2563 ip3->hop_limit -= 1;
2566 clib_net_to_host_u16 (ip0->payload_length) +
2567 vec_len (sl0->rewrite_bsid);
2569 clib_net_to_host_u16 (ip1->payload_length) +
2570 vec_len (sl1->rewrite_bsid);
2572 clib_net_to_host_u16 (ip2->payload_length) +
2573 vec_len (sl2->rewrite_bsid);
2575 clib_net_to_host_u16 (ip3->payload_length) +
2576 vec_len (sl3->rewrite_bsid);
2578 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2579 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2580 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2581 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2583 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2584 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2585 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2586 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2588 ip0->dst_address.as_u64[0] =
2589 (sr0->segments + sr0->segments_left)->as_u64[0];
2590 ip0->dst_address.as_u64[1] =
2591 (sr0->segments + sr0->segments_left)->as_u64[1];
2592 ip1->dst_address.as_u64[0] =
2593 (sr1->segments + sr1->segments_left)->as_u64[0];
2594 ip1->dst_address.as_u64[1] =
2595 (sr1->segments + sr1->segments_left)->as_u64[1];
2596 ip2->dst_address.as_u64[0] =
2597 (sr2->segments + sr2->segments_left)->as_u64[0];
2598 ip2->dst_address.as_u64[1] =
2599 (sr2->segments + sr2->segments_left)->as_u64[1];
2600 ip3->dst_address.as_u64[0] =
2601 (sr3->segments + sr3->segments_left)->as_u64[0];
2602 ip3->dst_address.as_u64[1] =
2603 (sr3->segments + sr3->segments_left)->as_u64[1];
2605 ip6_ext_header_t *ip_ext;
2606 if (ip0 + 1 == (void *) sr0)
2608 sr0->protocol = ip0->protocol;
2609 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2613 ip_ext = (void *) (ip0 + 1);
2614 sr0->protocol = ip_ext->next_hdr;
2615 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2618 if (ip1 + 1 == (void *) sr1)
2620 sr1->protocol = ip1->protocol;
2621 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2625 ip_ext = (void *) (ip2 + 1);
2626 sr2->protocol = ip_ext->next_hdr;
2627 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2630 if (ip2 + 1 == (void *) sr2)
2632 sr2->protocol = ip2->protocol;
2633 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2637 ip_ext = (void *) (ip2 + 1);
2638 sr2->protocol = ip_ext->next_hdr;
2639 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2642 if (ip3 + 1 == (void *) sr3)
2644 sr3->protocol = ip3->protocol;
2645 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2649 ip_ext = (void *) (ip3 + 1);
2650 sr3->protocol = ip_ext->next_hdr;
2651 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2656 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2658 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2660 sr_policy_rewrite_trace_t *tr =
2661 vlib_add_trace (vm, node, b0, sizeof (*tr));
2662 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2663 sizeof (tr->src.as_u8));
2664 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2665 sizeof (tr->dst.as_u8));
2668 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2670 sr_policy_rewrite_trace_t *tr =
2671 vlib_add_trace (vm, node, b1, sizeof (*tr));
2672 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2673 sizeof (tr->src.as_u8));
2674 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2675 sizeof (tr->dst.as_u8));
2678 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2680 sr_policy_rewrite_trace_t *tr =
2681 vlib_add_trace (vm, node, b2, sizeof (*tr));
2682 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2683 sizeof (tr->src.as_u8));
2684 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2685 sizeof (tr->dst.as_u8));
2688 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2690 sr_policy_rewrite_trace_t *tr =
2691 vlib_add_trace (vm, node, b3, sizeof (*tr));
2692 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2693 sizeof (tr->src.as_u8));
2694 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2695 sizeof (tr->dst.as_u8));
2699 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2700 n_left_to_next, bi0, bi1, bi2, bi3,
2701 next0, next1, next2, next3);
2704 /* Single loop for potentially the last three packets */
2705 while (n_left_from > 0 && n_left_to_next > 0)
2709 ip6_header_t *ip0 = 0;
2710 ip6_sr_header_t *sr0 = 0;
2712 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2720 n_left_to_next -= 1;
2722 b0 = vlib_get_buffer (vm, bi0);
2724 pool_elt_at_index (sm->sid_lists,
2725 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2726 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2727 vec_len (sl0->rewrite_bsid));
2729 ip0 = vlib_buffer_get_current (b0);
2731 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2733 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2734 ip6_ext_header_len (ip0 + 1));
2736 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2738 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2739 (void *) sr0 - (void *) ip0);
2740 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2741 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2743 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2745 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2746 ip0->hop_limit -= 1;
2748 clib_net_to_host_u16 (ip0->payload_length) +
2749 vec_len (sl0->rewrite_bsid);
2750 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2752 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2754 ip0->dst_address.as_u64[0] =
2755 (sr0->segments + sr0->segments_left)->as_u64[0];
2756 ip0->dst_address.as_u64[1] =
2757 (sr0->segments + sr0->segments_left)->as_u64[1];
2759 if (ip0 + 1 == (void *) sr0)
2761 sr0->protocol = ip0->protocol;
2762 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2766 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2767 sr0->protocol = ip_ext->next_hdr;
2768 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2771 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2772 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2774 sr_policy_rewrite_trace_t *tr =
2775 vlib_add_trace (vm, node, b0, sizeof (*tr));
2776 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2777 sizeof (tr->src.as_u8));
2778 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2779 sizeof (tr->dst.as_u8));
2784 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2785 n_left_to_next, bi0, next0);
2788 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2791 /* Update counters */
2792 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2793 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2795 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2796 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2798 return from_frame->n_vectors;
2802 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2803 .function = sr_policy_rewrite_b_insert,
2804 .name = "sr-pl-rewrite-b-insert",
2805 .vector_size = sizeof (u32),
2806 .format_trace = format_sr_policy_rewrite_trace,
2807 .type = VLIB_NODE_TYPE_INTERNAL,
2808 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2809 .error_strings = sr_policy_rewrite_error_strings,
2810 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2812 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2813 foreach_sr_policy_rewrite_next
2820 * @brief Function BSID encapsulation
2822 static_always_inline void
2823 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2826 ip6_sr_header_t * sr0, u32 * next0)
2828 ip6_address_t *new_dst0;
2830 if (PREDICT_FALSE (!sr0))
2831 goto error_bsid_encaps;
2833 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2835 if (PREDICT_TRUE (sr0->segments_left != 0))
2837 sr0->segments_left -= 1;
2838 new_dst0 = (ip6_address_t *) (sr0->segments);
2839 new_dst0 += sr0->segments_left;
2840 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2841 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2847 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2848 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2852 * @brief Graph node for applying a SR policy BSID - Encapsulation
2855 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2856 vlib_frame_t * from_frame)
2858 ip6_sr_main_t *sm = &sr_main;
2859 u32 n_left_from, next_index, *from, *to_next;
2861 from = vlib_frame_vector_args (from_frame);
2862 n_left_from = from_frame->n_vectors;
2864 next_index = node->cached_next_index;
2866 int encap_pkts = 0, bsid_pkts = 0;
2868 while (n_left_from > 0)
2872 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2875 while (n_left_from >= 8 && n_left_to_next >= 4)
2877 u32 bi0, bi1, bi2, bi3;
2878 vlib_buffer_t *b0, *b1, *b2, *b3;
2879 u32 next0, next1, next2, next3;
2880 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2881 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2882 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2883 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2884 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2885 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2887 /* Prefetch next iteration. */
2889 vlib_buffer_t *p4, *p5, *p6, *p7;
2891 p4 = vlib_get_buffer (vm, from[4]);
2892 p5 = vlib_get_buffer (vm, from[5]);
2893 p6 = vlib_get_buffer (vm, from[6]);
2894 p7 = vlib_get_buffer (vm, from[7]);
2896 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2897 vlib_prefetch_buffer_header (p4, LOAD);
2898 vlib_prefetch_buffer_header (p5, LOAD);
2899 vlib_prefetch_buffer_header (p6, LOAD);
2900 vlib_prefetch_buffer_header (p7, LOAD);
2902 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2903 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2904 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2905 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2908 to_next[0] = bi0 = from[0];
2909 to_next[1] = bi1 = from[1];
2910 to_next[2] = bi2 = from[2];
2911 to_next[3] = bi3 = from[3];
2915 n_left_to_next -= 4;
2917 b0 = vlib_get_buffer (vm, bi0);
2918 b1 = vlib_get_buffer (vm, bi1);
2919 b2 = vlib_get_buffer (vm, bi2);
2920 b3 = vlib_get_buffer (vm, bi3);
2923 pool_elt_at_index (sm->sid_lists,
2924 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2926 pool_elt_at_index (sm->sid_lists,
2927 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2929 pool_elt_at_index (sm->sid_lists,
2930 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2932 pool_elt_at_index (sm->sid_lists,
2933 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2934 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2935 vec_len (sl0->rewrite));
2936 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2937 vec_len (sl1->rewrite));
2938 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2939 vec_len (sl2->rewrite));
2940 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2941 vec_len (sl3->rewrite));
2943 ip0_encap = vlib_buffer_get_current (b0);
2944 ip1_encap = vlib_buffer_get_current (b1);
2945 ip2_encap = vlib_buffer_get_current (b2);
2946 ip3_encap = vlib_buffer_get_current (b3);
2948 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2949 IP_PROTOCOL_IPV6_ROUTE);
2950 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2951 IP_PROTOCOL_IPV6_ROUTE);
2952 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2953 IP_PROTOCOL_IPV6_ROUTE);
2954 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2955 IP_PROTOCOL_IPV6_ROUTE);
2957 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2958 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2959 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2960 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2962 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2963 sl0->rewrite, vec_len (sl0->rewrite));
2964 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2965 sl1->rewrite, vec_len (sl1->rewrite));
2966 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2967 sl2->rewrite, vec_len (sl2->rewrite));
2968 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2969 sl3->rewrite, vec_len (sl3->rewrite));
2971 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2972 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2973 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2974 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2976 ip0 = vlib_buffer_get_current (b0);
2977 ip1 = vlib_buffer_get_current (b1);
2978 ip2 = vlib_buffer_get_current (b2);
2979 ip3 = vlib_buffer_get_current (b3);
2981 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2982 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2983 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2984 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2986 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2988 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2990 sr_policy_rewrite_trace_t *tr =
2991 vlib_add_trace (vm, node, b0, sizeof (*tr));
2992 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2993 sizeof (tr->src.as_u8));
2994 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2995 sizeof (tr->dst.as_u8));
2998 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3000 sr_policy_rewrite_trace_t *tr =
3001 vlib_add_trace (vm, node, b1, sizeof (*tr));
3002 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3003 sizeof (tr->src.as_u8));
3004 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3005 sizeof (tr->dst.as_u8));
3008 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3010 sr_policy_rewrite_trace_t *tr =
3011 vlib_add_trace (vm, node, b2, sizeof (*tr));
3012 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3013 sizeof (tr->src.as_u8));
3014 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3015 sizeof (tr->dst.as_u8));
3018 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3020 sr_policy_rewrite_trace_t *tr =
3021 vlib_add_trace (vm, node, b3, sizeof (*tr));
3022 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3023 sizeof (tr->src.as_u8));
3024 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3025 sizeof (tr->dst.as_u8));
3030 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3031 n_left_to_next, bi0, bi1, bi2, bi3,
3032 next0, next1, next2, next3);
3035 /* Single loop for potentially the last three packets */
3036 while (n_left_from > 0 && n_left_to_next > 0)
3040 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3041 ip6_ext_header_t *prev0;
3042 ip6_sr_header_t *sr0;
3044 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3051 n_left_to_next -= 1;
3052 b0 = vlib_get_buffer (vm, bi0);
3055 pool_elt_at_index (sm->sid_lists,
3056 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3057 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3058 vec_len (sl0->rewrite));
3060 ip0_encap = vlib_buffer_get_current (b0);
3061 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3062 IP_PROTOCOL_IPV6_ROUTE);
3063 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3065 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3066 sl0->rewrite, vec_len (sl0->rewrite));
3067 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3069 ip0 = vlib_buffer_get_current (b0);
3071 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3073 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3074 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3076 sr_policy_rewrite_trace_t *tr =
3077 vlib_add_trace (vm, node, b0, sizeof (*tr));
3078 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3079 sizeof (tr->src.as_u8));
3080 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3081 sizeof (tr->dst.as_u8));
3085 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3086 n_left_to_next, bi0, next0);
3089 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3092 /* Update counters */
3093 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3094 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3096 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3097 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3100 return from_frame->n_vectors;
3104 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3105 .function = sr_policy_rewrite_b_encaps,
3106 .name = "sr-pl-rewrite-b-encaps",
3107 .vector_size = sizeof (u32),
3108 .format_trace = format_sr_policy_rewrite_trace,
3109 .type = VLIB_NODE_TYPE_INTERNAL,
3110 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3111 .error_strings = sr_policy_rewrite_error_strings,
3112 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3114 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3115 foreach_sr_policy_rewrite_next
3121 /*************************** SR Segment Lists DPOs ****************************/
3123 format_sr_segment_list_dpo (u8 * s, va_list * args)
3125 ip6_sr_main_t *sm = &sr_main;
3126 ip6_address_t *addr;
3129 index_t index = va_arg (*args, index_t);
3130 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3131 s = format (s, "SR: Segment List index:[%d]", index);
3132 s = format (s, "\n\tSegments:");
3134 sl = pool_elt_at_index (sm->sid_lists, index);
3136 s = format (s, "< ");
3137 vec_foreach (addr, sl->segments)
3139 s = format (s, "%U, ", format_ip6_address, addr);
3141 s = format (s, "\b\b > - ");
3142 s = format (s, "Weight: %u", sl->weight);
3147 const static dpo_vft_t sr_policy_rewrite_vft = {
3148 .dv_lock = sr_dpo_lock,
3149 .dv_unlock = sr_dpo_unlock,
3150 .dv_format = format_sr_segment_list_dpo,
3153 const static char *const sr_pr_encaps_ip6_nodes[] = {
3154 "sr-pl-rewrite-encaps",
3158 const static char *const sr_pr_encaps_ip4_nodes[] = {
3159 "sr-pl-rewrite-encaps-v4",
3163 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3164 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3165 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3168 const static char *const sr_pr_insert_ip6_nodes[] = {
3169 "sr-pl-rewrite-insert",
3173 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3174 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3177 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3178 "sr-pl-rewrite-b-insert",
3182 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3183 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3186 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3187 "sr-pl-rewrite-b-encaps",
3191 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3192 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3195 /********************* SR Policy Rewrite initialization ***********************/
3197 * @brief SR Policy Rewrite initialization
3200 sr_policy_rewrite_init (vlib_main_t * vm)
3202 ip6_sr_main_t *sm = &sr_main;
3204 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3205 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3206 sizeof (ip6_address_t));
3208 /* Init SR VPO DPOs type */
3209 sr_pr_encaps_dpo_type =
3210 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3212 sr_pr_insert_dpo_type =
3213 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3215 sr_pr_bsid_encaps_dpo_type =
3216 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3218 sr_pr_bsid_insert_dpo_type =
3219 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3221 /* Register the L2 encaps node used in HW redirect */
3222 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3224 sm->fib_table_ip6 = (u32) ~ 0;
3225 sm->fib_table_ip4 = (u32) ~ 0;
3230 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3234 * fd.io coding-style-patch-verification: ON
3237 * eval: (c-set-style "gnu")