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 /******************************* SR rewrite API *******************************/
524 /* Three functions for handling sr policies:
528 * All of them are API. CLI function on sr_policy_command_fn */
531 * @brief Create a new SR policy
533 * @param bsid is the bindingSID of the SR Policy
534 * @param segments is a vector of IPv6 address composing the segment list
535 * @param weight is the weight of the sid list. optional.
536 * @param behavior is the behavior of the SR policy. (default//spray)
537 * @param fib_table is the VRF where to install the FIB entry for the BSID
538 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
540 * @return 0 if correct, else error
543 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
544 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
546 ip6_sr_main_t *sm = &sr_main;
547 ip6_sr_policy_t *sr_policy = 0;
550 /* Search for existing keys (BSID) */
551 p = mhash_get (&sm->sr_policies_index_hash, bsid);
554 /* Add SR policy that already exists; complain */
558 /* Search collision in FIB entries */
559 /* Explanation: It might be possible that some other entity has already
560 * created a route for the BSID. This in theory is impossible, but in
561 * practise we could see it. Assert it and scream if needed */
563 .fp_proto = FIB_PROTOCOL_IP6,
570 /* Lookup the FIB index associated to the table selected */
571 u32 fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6,
573 (u32) ~ 0 ? fib_table : 0));
577 /* Lookup whether there exists an entry for the BSID */
578 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
579 if (FIB_NODE_INDEX_INVALID != fei)
580 return -12; //There is an entry for such lookup
582 /* Add an SR policy object */
583 pool_get (sm->sr_policies, sr_policy);
584 memset (sr_policy, 0, sizeof (*sr_policy));
585 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
586 sr_policy->type = behavior;
587 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
588 sr_policy->is_encap = is_encap;
591 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
594 /* Create a segment list and add the index to the SR policy */
595 create_sl (sr_policy, segments, weight, is_encap);
597 /* If FIB doesnt exist, create them */
598 if (sm->fib_table_ip6 == (u32) ~ 0)
600 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
601 "SRv6 steering of IP6 prefixes through BSIDs");
602 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
603 "SRv6 steering of IP4 prefixes through BSIDs");
606 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
607 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
608 update_lb (sr_policy);
609 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
610 update_replicate (sr_policy);
615 * @brief Delete a SR policy
617 * @param bsid is the bindingSID of the SR Policy
618 * @param index is the index of the SR policy
620 * @return 0 if correct, else error
623 sr_policy_del (ip6_address_t * bsid, u32 index)
625 ip6_sr_main_t *sm = &sr_main;
626 ip6_sr_policy_t *sr_policy = 0;
627 ip6_sr_sl_t *segment_list;
633 p = mhash_get (&sm->sr_policies_index_hash, bsid);
635 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
641 sr_policy = pool_elt_at_index (sm->sr_policies, index);
646 /* Remove BindingSID FIB entry */
648 .fp_proto = FIB_PROTOCOL_IP6,
651 .ip6 = sr_policy->bsid,
656 fib_table_entry_special_remove (fib_table_id_find_fib_index
657 (FIB_PROTOCOL_IP6, sr_policy->fib_table),
658 &pfx, FIB_SOURCE_SR);
660 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
662 if (sr_policy->is_encap)
663 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
665 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
667 dpo_reset (&sr_policy->bsid_dpo);
668 dpo_reset (&sr_policy->ip4_dpo);
669 dpo_reset (&sr_policy->ip6_dpo);
672 /* Clean SID Lists */
673 vec_foreach (sl_index, sr_policy->segments_lists)
675 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
676 vec_free (segment_list->segments);
677 vec_free (segment_list->rewrite);
678 vec_free (segment_list->rewrite_bsid);
679 pool_put_index (sm->sid_lists, *sl_index);
682 /* Remove SR policy entry */
683 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
684 pool_put (sm->sr_policies, sr_policy);
686 /* If FIB empty unlock it */
687 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
689 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6);
690 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6);
691 sm->fib_table_ip6 = (u32) ~ 0;
692 sm->fib_table_ip4 = (u32) ~ 0;
699 * @brief Modify an existing SR policy
701 * The possible modifications are adding a new Segment List, modifying an
702 * existing Segment List (modify the weight only) and delete a given
703 * Segment List from the SR Policy.
705 * @param bsid is the bindingSID of the SR Policy
706 * @param index is the index of the SR policy
707 * @param fib_table is the VRF where to install the FIB entry for the BSID
708 * @param operation is the operation to perform (among the top ones)
709 * @param segments is a vector of IPv6 address composing the segment list
710 * @param sl_index is the index of the Segment List to modify/delete
711 * @param weight is the weight of the sid list. optional.
712 * @param is_encap Mode. Encapsulation or SRH insertion.
714 * @return 0 if correct, else error
717 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
718 u8 operation, ip6_address_t * segments, u32 sl_index,
721 ip6_sr_main_t *sm = &sr_main;
722 ip6_sr_policy_t *sr_policy = 0;
723 ip6_sr_sl_t *segment_list;
724 u32 *sl_index_iterate;
729 p = mhash_get (&sm->sr_policies_index_hash, bsid);
731 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
737 sr_policy = pool_elt_at_index (sm->sr_policies, index);
742 if (operation == 1) /* Add SR List to an existing SR policy */
744 /* Create the new SL */
746 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
748 /* Create a new LB DPO */
749 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
750 update_lb (sr_policy);
751 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
752 update_replicate (sr_policy);
754 else if (operation == 2) /* Delete SR List from an existing SR policy */
756 /* Check that currently there are more than one SID list */
757 if (vec_len (sr_policy->segments_lists) == 1)
760 /* Check that the SR list does exist and is assigned to the sr policy */
761 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
762 if (*sl_index_iterate == sl_index)
765 if (*sl_index_iterate != sl_index)
768 /* Remove the lucky SR list that is being kicked out */
769 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
770 vec_free (segment_list->segments);
771 vec_free (segment_list->rewrite);
772 vec_free (segment_list->rewrite_bsid);
773 pool_put_index (sm->sid_lists, sl_index);
774 vec_del1 (sr_policy->segments_lists,
775 sl_index_iterate - sr_policy->segments_lists);
777 /* Create a new LB DPO */
778 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
779 update_lb (sr_policy);
780 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
781 update_replicate (sr_policy);
783 else if (operation == 3) /* Modify the weight of an existing SR List */
785 /* Find the corresponding SL */
786 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
787 if (*sl_index_iterate == sl_index)
790 if (*sl_index_iterate != sl_index)
793 /* Change the weight */
794 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
795 segment_list->weight = weight;
798 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
799 update_lb (sr_policy);
801 else /* Incorrect op. */
808 * @brief CLI for 'sr policies' command family
810 static clib_error_t *
811 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
812 vlib_cli_command_t * cmd)
815 char is_del = 0, is_add = 0, is_mod = 0;
817 ip6_address_t bsid, next_address;
818 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
819 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
820 ip6_address_t *segments = 0, *this_seg;
825 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
829 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
831 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
834 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
836 else if (!is_add && !policy_set
837 && unformat (input, "index %d", &sr_policy_index))
839 else if (unformat (input, "weight %d", &weight));
841 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
843 vec_add2 (segments, this_seg, 1);
844 clib_memcpy (this_seg->as_u8, next_address.as_u8,
847 else if (unformat (input, "add sl"))
849 else if (unformat (input, "del sl index %d", &sl_index))
851 else if (unformat (input, "mod sl index %d", &sl_index))
853 else if (fib_table == (u32) ~ 0
854 && unformat (input, "fib-table %d", &fib_table));
855 else if (unformat (input, "encap"))
857 else if (unformat (input, "insert"))
859 else if (unformat (input, "spray"))
865 if (!is_add && !is_mod && !is_del)
866 return clib_error_return (0, "Incorrect CLI");
869 return clib_error_return (0, "No SR policy BSID or index specified");
873 if (vec_len (segments) == 0)
874 return clib_error_return (0, "No Segment List specified");
875 rv = sr_policy_add (&bsid, segments, weight,
876 (is_spray ? SR_POLICY_TYPE_SPRAY :
877 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
880 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
885 return clib_error_return (0, "No SL modification specified");
886 if (operation != 1 && sl_index == (u32) ~ 0)
887 return clib_error_return (0, "No Segment List index specified");
888 if (operation == 1 && vec_len (segments) == 0)
889 return clib_error_return (0, "No Segment List specified");
890 if (operation == 3 && weight == (u32) ~ 0)
891 return clib_error_return (0, "No new weight for the SL specified");
892 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
893 sr_policy_index, fib_table, operation, segments,
904 return clib_error_return (0,
905 "There is already a FIB entry for the BindingSID address.\n"
906 "The SR policy could not be created.");
908 return clib_error_return (0, "The specified FIB table does not exist.");
910 return clib_error_return (0,
911 "The selected SR policy only contains ONE segment list. "
912 "Please remove the SR policy instead");
914 return clib_error_return (0,
915 "Could not delete the segment list. "
916 "It is not associated with that SR policy.");
918 return clib_error_return (0,
919 "Could not modify the segment list. "
920 "The given SL is not associated with such SR policy.");
922 return clib_error_return (0, "BUG: sr policy returns %d", rv);
928 VLIB_CLI_COMMAND (sr_policy_command, static) = {
930 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
931 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
933 "Manipulation of SR policies.\n"
934 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
935 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
936 "Segment Routing policies might be of type encapsulation or srh insertion\n"
937 "Each SR policy will be associated with a unique BindingSID.\n"
938 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
939 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
940 "The add command will create a SR policy with its first segment list (sl)\n"
941 "The mod command allows you to add, remove, or modify the existing segment lists\n"
942 "within an SR policy.\n"
943 "The del command allows you to delete a SR policy along with all its associated\n"
945 .function = sr_policy_command_fn,
950 * @brief CLI to display onscreen all the SR policies
952 static clib_error_t *
953 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
954 vlib_cli_command_t * cmd)
956 ip6_sr_main_t *sm = &sr_main;
958 ip6_sr_sl_t *segment_list = 0;
959 ip6_sr_policy_t *sr_policy = 0;
960 ip6_sr_policy_t **vec_policies = 0;
965 vlib_cli_output (vm, "SR policies:");
968 pool_foreach (sr_policy, sm->sr_policies,
969 {vec_add1 (vec_policies, sr_policy); } );
972 vec_foreach_index (i, vec_policies)
974 sr_policy = vec_policies[i];
975 vlib_cli_output (vm, "[%u].-\tBSID: %U",
976 (u32) (sr_policy - sm->sr_policies),
977 format_ip6_address, &sr_policy->bsid);
978 vlib_cli_output (vm, "\tBehavior: %s",
979 (sr_policy->is_encap ? "Encapsulation" :
981 vlib_cli_output (vm, "\tType: %s",
983 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
984 vlib_cli_output (vm, "\tFIB table: %u",
985 (sr_policy->fib_table !=
986 (u32) ~ 0 ? sr_policy->fib_table : 0));
987 vlib_cli_output (vm, "\tSegment Lists:");
988 vec_foreach (sl_index, sr_policy->segments_lists)
991 s = format (s, "\t[%u].- ", *sl_index);
992 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
993 s = format (s, "< ");
994 vec_foreach (addr, segment_list->segments)
996 s = format (s, "%U, ", format_ip6_address, addr);
998 s = format (s, "\b\b > ");
999 s = format (s, "weight: %u", segment_list->weight);
1000 vlib_cli_output (vm, " %s", s);
1002 vlib_cli_output (vm, "-----------");
1008 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1009 .path = "show sr policies",
1010 .short_help = "show sr policies",
1011 .function = show_sr_policies_command_fn,
1015 /*************************** SR rewrite graph node ****************************/
1017 * @brief Trace for the SR Policy Rewrite graph node
1020 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1023 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1024 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1025 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1028 (s, "SR-policy-rewrite: src %U dst %U",
1029 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1035 * @brief IPv6 encapsulation processing as per RFC2473
1037 static_always_inline void
1038 encaps_processing_v6 (vlib_node_runtime_t * node,
1040 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1044 ip0_encap->hop_limit -= 1;
1046 ip0->payload_length + sizeof (ip6_header_t) +
1047 clib_net_to_host_u16 (ip0_encap->payload_length);
1048 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1049 ip0->ip_version_traffic_class_and_flow_label =
1050 ip0_encap->ip_version_traffic_class_and_flow_label;
1054 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1057 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1058 vlib_frame_t * from_frame)
1060 ip6_sr_main_t *sm = &sr_main;
1061 u32 n_left_from, next_index, *from, *to_next;
1063 from = vlib_frame_vector_args (from_frame);
1064 n_left_from = from_frame->n_vectors;
1066 next_index = node->cached_next_index;
1068 int encap_pkts = 0, bsid_pkts = 0;
1070 while (n_left_from > 0)
1074 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1077 while (n_left_from >= 8 && n_left_to_next >= 4)
1079 u32 bi0, bi1, bi2, bi3;
1080 vlib_buffer_t *b0, *b1, *b2, *b3;
1081 u32 next0, next1, next2, next3;
1082 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1083 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1084 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1085 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1087 /* Prefetch next iteration. */
1089 vlib_buffer_t *p4, *p5, *p6, *p7;
1091 p4 = vlib_get_buffer (vm, from[4]);
1092 p5 = vlib_get_buffer (vm, from[5]);
1093 p6 = vlib_get_buffer (vm, from[6]);
1094 p7 = vlib_get_buffer (vm, from[7]);
1096 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1097 vlib_prefetch_buffer_header (p4, LOAD);
1098 vlib_prefetch_buffer_header (p5, LOAD);
1099 vlib_prefetch_buffer_header (p6, LOAD);
1100 vlib_prefetch_buffer_header (p7, LOAD);
1102 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1103 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1104 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1105 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1108 to_next[0] = bi0 = from[0];
1109 to_next[1] = bi1 = from[1];
1110 to_next[2] = bi2 = from[2];
1111 to_next[3] = bi3 = from[3];
1115 n_left_to_next -= 4;
1117 b0 = vlib_get_buffer (vm, bi0);
1118 b1 = vlib_get_buffer (vm, bi1);
1119 b2 = vlib_get_buffer (vm, bi2);
1120 b3 = vlib_get_buffer (vm, bi3);
1123 pool_elt_at_index (sm->sid_lists,
1124 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1126 pool_elt_at_index (sm->sid_lists,
1127 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1129 pool_elt_at_index (sm->sid_lists,
1130 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1132 pool_elt_at_index (sm->sid_lists,
1133 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1135 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1136 vec_len (sl0->rewrite));
1137 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1138 vec_len (sl1->rewrite));
1139 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1140 vec_len (sl2->rewrite));
1141 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1142 vec_len (sl3->rewrite));
1144 ip0_encap = vlib_buffer_get_current (b0);
1145 ip1_encap = vlib_buffer_get_current (b1);
1146 ip2_encap = vlib_buffer_get_current (b2);
1147 ip3_encap = vlib_buffer_get_current (b3);
1149 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1150 sl0->rewrite, vec_len (sl0->rewrite));
1151 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1152 sl1->rewrite, vec_len (sl1->rewrite));
1153 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1154 sl2->rewrite, vec_len (sl2->rewrite));
1155 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1156 sl3->rewrite, vec_len (sl3->rewrite));
1158 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1159 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1160 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1161 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1163 ip0 = vlib_buffer_get_current (b0);
1164 ip1 = vlib_buffer_get_current (b1);
1165 ip2 = vlib_buffer_get_current (b2);
1166 ip3 = vlib_buffer_get_current (b3);
1168 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1169 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1170 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1171 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1173 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1175 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1177 sr_policy_rewrite_trace_t *tr =
1178 vlib_add_trace (vm, node, b0, sizeof (*tr));
1179 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1180 sizeof (tr->src.as_u8));
1181 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1182 sizeof (tr->dst.as_u8));
1185 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1187 sr_policy_rewrite_trace_t *tr =
1188 vlib_add_trace (vm, node, b1, sizeof (*tr));
1189 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1190 sizeof (tr->src.as_u8));
1191 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1192 sizeof (tr->dst.as_u8));
1195 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1197 sr_policy_rewrite_trace_t *tr =
1198 vlib_add_trace (vm, node, b2, sizeof (*tr));
1199 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1200 sizeof (tr->src.as_u8));
1201 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1202 sizeof (tr->dst.as_u8));
1205 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1207 sr_policy_rewrite_trace_t *tr =
1208 vlib_add_trace (vm, node, b3, sizeof (*tr));
1209 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1210 sizeof (tr->src.as_u8));
1211 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1212 sizeof (tr->dst.as_u8));
1217 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1218 n_left_to_next, bi0, bi1, bi2, bi3,
1219 next0, next1, next2, next3);
1222 /* Single loop for potentially the last three packets */
1223 while (n_left_from > 0 && n_left_to_next > 0)
1227 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1229 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1236 n_left_to_next -= 1;
1237 b0 = vlib_get_buffer (vm, bi0);
1240 pool_elt_at_index (sm->sid_lists,
1241 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1242 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1243 vec_len (sl0->rewrite));
1245 ip0_encap = vlib_buffer_get_current (b0);
1247 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1248 sl0->rewrite, vec_len (sl0->rewrite));
1249 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1251 ip0 = vlib_buffer_get_current (b0);
1253 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1255 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1256 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1258 sr_policy_rewrite_trace_t *tr =
1259 vlib_add_trace (vm, node, b0, sizeof (*tr));
1260 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1261 sizeof (tr->src.as_u8));
1262 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1263 sizeof (tr->dst.as_u8));
1267 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1268 n_left_to_next, bi0, next0);
1271 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1274 /* Update counters */
1275 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1276 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1278 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1279 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1282 return from_frame->n_vectors;
1286 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1287 .function = sr_policy_rewrite_encaps,
1288 .name = "sr-pl-rewrite-encaps",
1289 .vector_size = sizeof (u32),
1290 .format_trace = format_sr_policy_rewrite_trace,
1291 .type = VLIB_NODE_TYPE_INTERNAL,
1292 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1293 .error_strings = sr_policy_rewrite_error_strings,
1294 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1296 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1297 foreach_sr_policy_rewrite_next
1304 * @brief IPv4 encapsulation processing as per RFC2473
1306 static_always_inline void
1307 encaps_processing_v4 (vlib_node_runtime_t * node,
1309 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1312 ip6_sr_header_t *sr0;
1316 /* Inner IPv4: Decrement TTL & update checksum */
1317 ip0_encap->ttl -= 1;
1318 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1319 checksum0 += checksum0 >= 0xffff;
1320 ip0_encap->checksum = checksum0;
1322 /* Outer IPv6: Update length, FL, proto */
1323 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1324 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1325 ip0->ip_version_traffic_class_and_flow_label =
1326 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1327 ((ip0_encap->tos & 0xFF) << 20));
1328 sr0 = (void *) (ip0 + 1);
1329 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1333 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1336 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1337 vlib_frame_t * from_frame)
1339 ip6_sr_main_t *sm = &sr_main;
1340 u32 n_left_from, next_index, *from, *to_next;
1342 from = vlib_frame_vector_args (from_frame);
1343 n_left_from = from_frame->n_vectors;
1345 next_index = node->cached_next_index;
1347 int encap_pkts = 0, bsid_pkts = 0;
1349 while (n_left_from > 0)
1353 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1356 while (n_left_from >= 8 && n_left_to_next >= 4)
1358 u32 bi0, bi1, bi2, bi3;
1359 vlib_buffer_t *b0, *b1, *b2, *b3;
1360 u32 next0, next1, next2, next3;
1361 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1362 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1363 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1364 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1366 /* Prefetch next iteration. */
1368 vlib_buffer_t *p4, *p5, *p6, *p7;
1370 p4 = vlib_get_buffer (vm, from[4]);
1371 p5 = vlib_get_buffer (vm, from[5]);
1372 p6 = vlib_get_buffer (vm, from[6]);
1373 p7 = vlib_get_buffer (vm, from[7]);
1375 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1376 vlib_prefetch_buffer_header (p4, LOAD);
1377 vlib_prefetch_buffer_header (p5, LOAD);
1378 vlib_prefetch_buffer_header (p6, LOAD);
1379 vlib_prefetch_buffer_header (p7, LOAD);
1381 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1382 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1383 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1384 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1387 to_next[0] = bi0 = from[0];
1388 to_next[1] = bi1 = from[1];
1389 to_next[2] = bi2 = from[2];
1390 to_next[3] = bi3 = from[3];
1394 n_left_to_next -= 4;
1396 b0 = vlib_get_buffer (vm, bi0);
1397 b1 = vlib_get_buffer (vm, bi1);
1398 b2 = vlib_get_buffer (vm, bi2);
1399 b3 = vlib_get_buffer (vm, bi3);
1402 pool_elt_at_index (sm->sid_lists,
1403 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1405 pool_elt_at_index (sm->sid_lists,
1406 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1408 pool_elt_at_index (sm->sid_lists,
1409 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1411 pool_elt_at_index (sm->sid_lists,
1412 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1413 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1414 vec_len (sl0->rewrite));
1415 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1416 vec_len (sl1->rewrite));
1417 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1418 vec_len (sl2->rewrite));
1419 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1420 vec_len (sl3->rewrite));
1422 ip0_encap = vlib_buffer_get_current (b0);
1423 ip1_encap = vlib_buffer_get_current (b1);
1424 ip2_encap = vlib_buffer_get_current (b2);
1425 ip3_encap = vlib_buffer_get_current (b3);
1427 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1428 sl0->rewrite, vec_len (sl0->rewrite));
1429 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1430 sl1->rewrite, vec_len (sl1->rewrite));
1431 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1432 sl2->rewrite, vec_len (sl2->rewrite));
1433 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1434 sl3->rewrite, vec_len (sl3->rewrite));
1436 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1437 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1438 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1439 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1441 ip0 = vlib_buffer_get_current (b0);
1442 ip1 = vlib_buffer_get_current (b1);
1443 ip2 = vlib_buffer_get_current (b2);
1444 ip3 = vlib_buffer_get_current (b3);
1446 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1447 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1448 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1449 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1451 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1453 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1455 sr_policy_rewrite_trace_t *tr =
1456 vlib_add_trace (vm, node, b0, sizeof (*tr));
1457 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1458 sizeof (tr->src.as_u8));
1459 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1460 sizeof (tr->dst.as_u8));
1463 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1465 sr_policy_rewrite_trace_t *tr =
1466 vlib_add_trace (vm, node, b1, sizeof (*tr));
1467 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1468 sizeof (tr->src.as_u8));
1469 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1470 sizeof (tr->dst.as_u8));
1473 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1475 sr_policy_rewrite_trace_t *tr =
1476 vlib_add_trace (vm, node, b2, sizeof (*tr));
1477 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1478 sizeof (tr->src.as_u8));
1479 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1480 sizeof (tr->dst.as_u8));
1483 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1485 sr_policy_rewrite_trace_t *tr =
1486 vlib_add_trace (vm, node, b3, sizeof (*tr));
1487 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1488 sizeof (tr->src.as_u8));
1489 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1490 sizeof (tr->dst.as_u8));
1495 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1496 n_left_to_next, bi0, bi1, bi2, bi3,
1497 next0, next1, next2, next3);
1500 /* Single loop for potentially the last three packets */
1501 while (n_left_from > 0 && n_left_to_next > 0)
1505 ip6_header_t *ip0 = 0;
1506 ip4_header_t *ip0_encap = 0;
1508 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1515 n_left_to_next -= 1;
1516 b0 = vlib_get_buffer (vm, bi0);
1519 pool_elt_at_index (sm->sid_lists,
1520 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1521 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1522 vec_len (sl0->rewrite));
1524 ip0_encap = vlib_buffer_get_current (b0);
1526 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1527 sl0->rewrite, vec_len (sl0->rewrite));
1528 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1530 ip0 = vlib_buffer_get_current (b0);
1532 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1534 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1535 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1537 sr_policy_rewrite_trace_t *tr =
1538 vlib_add_trace (vm, node, b0, sizeof (*tr));
1539 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1540 sizeof (tr->src.as_u8));
1541 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1542 sizeof (tr->dst.as_u8));
1546 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1547 n_left_to_next, bi0, next0);
1550 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1553 /* Update counters */
1554 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1555 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1557 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1558 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1561 return from_frame->n_vectors;
1565 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1566 .function = sr_policy_rewrite_encaps_v4,
1567 .name = "sr-pl-rewrite-encaps-v4",
1568 .vector_size = sizeof (u32),
1569 .format_trace = format_sr_policy_rewrite_trace,
1570 .type = VLIB_NODE_TYPE_INTERNAL,
1571 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1572 .error_strings = sr_policy_rewrite_error_strings,
1573 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1575 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1576 foreach_sr_policy_rewrite_next
1583 ip_flow_hash (void *data)
1585 ip4_header_t *iph = (ip4_header_t *) data;
1587 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1588 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1590 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1596 return (*((u64 *) m) & 0xffffffffffff);
1600 l2_flow_hash (vlib_buffer_t * b0)
1602 ethernet_header_t *eh;
1604 uword is_ip, eh_size;
1607 eh = vlib_buffer_get_current (b0);
1608 eh_type = clib_net_to_host_u16 (eh->type);
1609 eh_size = ethernet_buffer_header_size (b0);
1611 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1613 /* since we have 2 cache lines, use them */
1615 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1619 b = mac_to_u64 ((u8 *) eh->dst_address);
1620 c = mac_to_u64 ((u8 *) eh->src_address);
1621 hash_mix64 (a, b, c);
1627 * @brief Graph node for applying a SR policy into a L2 frame
1630 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1631 vlib_frame_t * from_frame)
1633 ip6_sr_main_t *sm = &sr_main;
1634 u32 n_left_from, next_index, *from, *to_next;
1636 from = vlib_frame_vector_args (from_frame);
1637 n_left_from = from_frame->n_vectors;
1639 next_index = node->cached_next_index;
1641 int encap_pkts = 0, bsid_pkts = 0;
1643 while (n_left_from > 0)
1647 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1650 while (n_left_from >= 8 && n_left_to_next >= 4)
1652 u32 bi0, bi1, bi2, bi3;
1653 vlib_buffer_t *b0, *b1, *b2, *b3;
1654 u32 next0, next1, next2, next3;
1655 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1656 ethernet_header_t *en0, *en1, *en2, *en3;
1657 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1658 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1659 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1660 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1662 /* Prefetch next iteration. */
1664 vlib_buffer_t *p4, *p5, *p6, *p7;
1666 p4 = vlib_get_buffer (vm, from[4]);
1667 p5 = vlib_get_buffer (vm, from[5]);
1668 p6 = vlib_get_buffer (vm, from[6]);
1669 p7 = vlib_get_buffer (vm, from[7]);
1671 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1672 vlib_prefetch_buffer_header (p4, LOAD);
1673 vlib_prefetch_buffer_header (p5, LOAD);
1674 vlib_prefetch_buffer_header (p6, LOAD);
1675 vlib_prefetch_buffer_header (p7, LOAD);
1677 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1678 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1679 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1680 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1683 to_next[0] = bi0 = from[0];
1684 to_next[1] = bi1 = from[1];
1685 to_next[2] = bi2 = from[2];
1686 to_next[3] = bi3 = from[3];
1690 n_left_to_next -= 4;
1692 b0 = vlib_get_buffer (vm, bi0);
1693 b1 = vlib_get_buffer (vm, bi1);
1694 b2 = vlib_get_buffer (vm, bi2);
1695 b3 = vlib_get_buffer (vm, bi3);
1697 sp0 = pool_elt_at_index (sm->sr_policies,
1698 sm->sw_iface_sr_policies[vnet_buffer
1702 sp1 = pool_elt_at_index (sm->sr_policies,
1703 sm->sw_iface_sr_policies[vnet_buffer
1707 sp2 = pool_elt_at_index (sm->sr_policies,
1708 sm->sw_iface_sr_policies[vnet_buffer
1712 sp3 = pool_elt_at_index (sm->sr_policies,
1713 sm->sw_iface_sr_policies[vnet_buffer
1717 if (vec_len (sp0->segments_lists) == 1)
1718 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1721 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1722 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1723 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1724 (vec_len (sp0->segments_lists) - 1))];
1727 if (vec_len (sp1->segments_lists) == 1)
1728 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1731 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1732 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1733 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1734 (vec_len (sp1->segments_lists) - 1))];
1737 if (vec_len (sp2->segments_lists) == 1)
1738 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1741 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1742 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1743 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1744 (vec_len (sp2->segments_lists) - 1))];
1747 if (vec_len (sp3->segments_lists) == 1)
1748 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1751 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1752 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1753 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1754 (vec_len (sp3->segments_lists) - 1))];
1758 pool_elt_at_index (sm->sid_lists,
1759 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1761 pool_elt_at_index (sm->sid_lists,
1762 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1764 pool_elt_at_index (sm->sid_lists,
1765 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1767 pool_elt_at_index (sm->sid_lists,
1768 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1770 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1771 vec_len (sl0->rewrite));
1772 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1773 vec_len (sl1->rewrite));
1774 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1775 vec_len (sl2->rewrite));
1776 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1777 vec_len (sl3->rewrite));
1779 en0 = vlib_buffer_get_current (b0);
1780 en1 = vlib_buffer_get_current (b1);
1781 en2 = vlib_buffer_get_current (b2);
1782 en3 = vlib_buffer_get_current (b3);
1784 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1785 vec_len (sl0->rewrite));
1786 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1787 vec_len (sl1->rewrite));
1788 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1789 vec_len (sl2->rewrite));
1790 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1791 vec_len (sl3->rewrite));
1793 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1794 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1795 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1796 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1798 ip0 = vlib_buffer_get_current (b0);
1799 ip1 = vlib_buffer_get_current (b1);
1800 ip2 = vlib_buffer_get_current (b2);
1801 ip3 = vlib_buffer_get_current (b3);
1803 ip0->payload_length =
1804 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1805 ip1->payload_length =
1806 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1807 ip2->payload_length =
1808 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1809 ip3->payload_length =
1810 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1812 sr0 = (void *) (ip0 + 1);
1813 sr1 = (void *) (ip1 + 1);
1814 sr2 = (void *) (ip2 + 1);
1815 sr3 = (void *) (ip3 + 1);
1817 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1818 IP_PROTOCOL_IP6_NONXT;
1820 /* Which Traffic class and flow label do I set ? */
1821 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1823 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1825 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1827 sr_policy_rewrite_trace_t *tr =
1828 vlib_add_trace (vm, node, b0, sizeof (*tr));
1829 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1830 sizeof (tr->src.as_u8));
1831 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1832 sizeof (tr->dst.as_u8));
1835 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1837 sr_policy_rewrite_trace_t *tr =
1838 vlib_add_trace (vm, node, b1, sizeof (*tr));
1839 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1840 sizeof (tr->src.as_u8));
1841 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1842 sizeof (tr->dst.as_u8));
1845 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1847 sr_policy_rewrite_trace_t *tr =
1848 vlib_add_trace (vm, node, b2, sizeof (*tr));
1849 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1850 sizeof (tr->src.as_u8));
1851 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1852 sizeof (tr->dst.as_u8));
1855 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1857 sr_policy_rewrite_trace_t *tr =
1858 vlib_add_trace (vm, node, b3, sizeof (*tr));
1859 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1860 sizeof (tr->src.as_u8));
1861 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1862 sizeof (tr->dst.as_u8));
1867 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1868 n_left_to_next, bi0, bi1, bi2, bi3,
1869 next0, next1, next2, next3);
1872 /* Single loop for potentially the last three packets */
1873 while (n_left_from > 0 && n_left_to_next > 0)
1877 ip6_header_t *ip0 = 0;
1878 ip6_sr_header_t *sr0;
1879 ethernet_header_t *en0;
1880 ip6_sr_policy_t *sp0;
1882 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1889 n_left_to_next -= 1;
1890 b0 = vlib_get_buffer (vm, bi0);
1892 /* Find the SR policy */
1893 sp0 = pool_elt_at_index (sm->sr_policies,
1894 sm->sw_iface_sr_policies[vnet_buffer
1898 /* In case there is more than one SL, LB among them */
1899 if (vec_len (sp0->segments_lists) == 1)
1900 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1903 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1904 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1905 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1906 (vec_len (sp0->segments_lists) - 1))];
1909 pool_elt_at_index (sm->sid_lists,
1910 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1911 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1912 vec_len (sl0->rewrite));
1914 en0 = vlib_buffer_get_current (b0);
1916 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1917 vec_len (sl0->rewrite));
1919 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1921 ip0 = vlib_buffer_get_current (b0);
1923 ip0->payload_length =
1924 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1926 sr0 = (void *) (ip0 + 1);
1927 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1929 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1930 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1932 sr_policy_rewrite_trace_t *tr =
1933 vlib_add_trace (vm, node, b0, sizeof (*tr));
1934 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1935 sizeof (tr->src.as_u8));
1936 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1937 sizeof (tr->dst.as_u8));
1941 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1942 n_left_to_next, bi0, next0);
1945 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1948 /* Update counters */
1949 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1950 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1952 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1953 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1956 return from_frame->n_vectors;
1960 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1961 .function = sr_policy_rewrite_encaps_l2,
1962 .name = "sr-pl-rewrite-encaps-l2",
1963 .vector_size = sizeof (u32),
1964 .format_trace = format_sr_policy_rewrite_trace,
1965 .type = VLIB_NODE_TYPE_INTERNAL,
1966 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1967 .error_strings = sr_policy_rewrite_error_strings,
1968 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1970 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1971 foreach_sr_policy_rewrite_next
1978 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1981 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1982 vlib_frame_t * from_frame)
1984 ip6_sr_main_t *sm = &sr_main;
1985 u32 n_left_from, next_index, *from, *to_next;
1987 from = vlib_frame_vector_args (from_frame);
1988 n_left_from = from_frame->n_vectors;
1990 next_index = node->cached_next_index;
1992 int insert_pkts = 0, bsid_pkts = 0;
1994 while (n_left_from > 0)
1998 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2001 while (n_left_from >= 8 && n_left_to_next >= 4)
2003 u32 bi0, bi1, bi2, bi3;
2004 vlib_buffer_t *b0, *b1, *b2, *b3;
2005 u32 next0, next1, next2, next3;
2006 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2007 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2008 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2009 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2010 u16 new_l0, new_l1, new_l2, new_l3;
2012 /* Prefetch next iteration. */
2014 vlib_buffer_t *p4, *p5, *p6, *p7;
2016 p4 = vlib_get_buffer (vm, from[4]);
2017 p5 = vlib_get_buffer (vm, from[5]);
2018 p6 = vlib_get_buffer (vm, from[6]);
2019 p7 = vlib_get_buffer (vm, from[7]);
2021 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2022 vlib_prefetch_buffer_header (p4, LOAD);
2023 vlib_prefetch_buffer_header (p5, LOAD);
2024 vlib_prefetch_buffer_header (p6, LOAD);
2025 vlib_prefetch_buffer_header (p7, LOAD);
2027 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2028 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2029 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2030 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2033 to_next[0] = bi0 = from[0];
2034 to_next[1] = bi1 = from[1];
2035 to_next[2] = bi2 = from[2];
2036 to_next[3] = bi3 = from[3];
2040 n_left_to_next -= 4;
2042 b0 = vlib_get_buffer (vm, bi0);
2043 b1 = vlib_get_buffer (vm, bi1);
2044 b2 = vlib_get_buffer (vm, bi2);
2045 b3 = vlib_get_buffer (vm, bi3);
2048 pool_elt_at_index (sm->sid_lists,
2049 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2051 pool_elt_at_index (sm->sid_lists,
2052 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2054 pool_elt_at_index (sm->sid_lists,
2055 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2057 pool_elt_at_index (sm->sid_lists,
2058 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2059 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2060 vec_len (sl0->rewrite));
2061 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2062 vec_len (sl1->rewrite));
2063 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2064 vec_len (sl2->rewrite));
2065 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2066 vec_len (sl3->rewrite));
2068 ip0 = vlib_buffer_get_current (b0);
2069 ip1 = vlib_buffer_get_current (b1);
2070 ip2 = vlib_buffer_get_current (b2);
2071 ip3 = vlib_buffer_get_current (b3);
2073 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2075 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2076 ip6_ext_header_len (ip0 + 1));
2078 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2080 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2082 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2083 ip6_ext_header_len (ip1 + 1));
2085 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2087 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2089 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2090 ip6_ext_header_len (ip2 + 1));
2092 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2094 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2096 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2097 ip6_ext_header_len (ip3 + 1));
2099 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2101 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2102 (void *) sr0 - (void *) ip0);
2103 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2104 (void *) sr1 - (void *) ip1);
2105 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2106 (void *) sr2 - (void *) ip2);
2107 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2108 (void *) sr3 - (void *) ip3);
2110 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2111 vec_len (sl0->rewrite));
2112 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2113 vec_len (sl1->rewrite));
2114 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2115 vec_len (sl2->rewrite));
2116 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2117 vec_len (sl3->rewrite));
2119 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2120 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2121 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2122 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2124 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2125 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2126 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2127 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2129 ip0->hop_limit -= 1;
2130 ip1->hop_limit -= 1;
2131 ip2->hop_limit -= 1;
2132 ip3->hop_limit -= 1;
2135 clib_net_to_host_u16 (ip0->payload_length) +
2136 vec_len (sl0->rewrite);
2138 clib_net_to_host_u16 (ip1->payload_length) +
2139 vec_len (sl1->rewrite);
2141 clib_net_to_host_u16 (ip2->payload_length) +
2142 vec_len (sl2->rewrite);
2144 clib_net_to_host_u16 (ip3->payload_length) +
2145 vec_len (sl3->rewrite);
2147 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2148 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2149 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2150 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2152 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2153 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2154 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2155 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2157 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2158 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2159 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2160 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2161 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2162 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2163 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2164 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2166 ip0->dst_address.as_u64[0] =
2167 (sr0->segments + sr0->segments_left)->as_u64[0];
2168 ip0->dst_address.as_u64[1] =
2169 (sr0->segments + sr0->segments_left)->as_u64[1];
2170 ip1->dst_address.as_u64[0] =
2171 (sr1->segments + sr1->segments_left)->as_u64[0];
2172 ip1->dst_address.as_u64[1] =
2173 (sr1->segments + sr1->segments_left)->as_u64[1];
2174 ip2->dst_address.as_u64[0] =
2175 (sr2->segments + sr2->segments_left)->as_u64[0];
2176 ip2->dst_address.as_u64[1] =
2177 (sr2->segments + sr2->segments_left)->as_u64[1];
2178 ip3->dst_address.as_u64[0] =
2179 (sr3->segments + sr3->segments_left)->as_u64[0];
2180 ip3->dst_address.as_u64[1] =
2181 (sr3->segments + sr3->segments_left)->as_u64[1];
2183 ip6_ext_header_t *ip_ext;
2184 if (ip0 + 1 == (void *) sr0)
2186 sr0->protocol = ip0->protocol;
2187 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2191 ip_ext = (void *) (ip0 + 1);
2192 sr0->protocol = ip_ext->next_hdr;
2193 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2196 if (ip1 + 1 == (void *) sr1)
2198 sr1->protocol = ip1->protocol;
2199 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2203 ip_ext = (void *) (ip2 + 1);
2204 sr2->protocol = ip_ext->next_hdr;
2205 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2208 if (ip2 + 1 == (void *) sr2)
2210 sr2->protocol = ip2->protocol;
2211 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2215 ip_ext = (void *) (ip2 + 1);
2216 sr2->protocol = ip_ext->next_hdr;
2217 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2220 if (ip3 + 1 == (void *) sr3)
2222 sr3->protocol = ip3->protocol;
2223 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2227 ip_ext = (void *) (ip3 + 1);
2228 sr3->protocol = ip_ext->next_hdr;
2229 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2234 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2236 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2238 sr_policy_rewrite_trace_t *tr =
2239 vlib_add_trace (vm, node, b0, sizeof (*tr));
2240 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2241 sizeof (tr->src.as_u8));
2242 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2243 sizeof (tr->dst.as_u8));
2246 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2248 sr_policy_rewrite_trace_t *tr =
2249 vlib_add_trace (vm, node, b1, sizeof (*tr));
2250 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2251 sizeof (tr->src.as_u8));
2252 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2253 sizeof (tr->dst.as_u8));
2256 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2258 sr_policy_rewrite_trace_t *tr =
2259 vlib_add_trace (vm, node, b2, sizeof (*tr));
2260 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2261 sizeof (tr->src.as_u8));
2262 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2263 sizeof (tr->dst.as_u8));
2266 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2268 sr_policy_rewrite_trace_t *tr =
2269 vlib_add_trace (vm, node, b3, sizeof (*tr));
2270 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2271 sizeof (tr->src.as_u8));
2272 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2273 sizeof (tr->dst.as_u8));
2277 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2278 n_left_to_next, bi0, bi1, bi2, bi3,
2279 next0, next1, next2, next3);
2282 /* Single loop for potentially the last three packets */
2283 while (n_left_from > 0 && n_left_to_next > 0)
2287 ip6_header_t *ip0 = 0;
2288 ip6_sr_header_t *sr0 = 0;
2290 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2298 n_left_to_next -= 1;
2300 b0 = vlib_get_buffer (vm, bi0);
2302 pool_elt_at_index (sm->sid_lists,
2303 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2304 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2305 vec_len (sl0->rewrite));
2307 ip0 = vlib_buffer_get_current (b0);
2309 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2311 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2312 ip6_ext_header_len (ip0 + 1));
2314 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2316 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2317 (void *) sr0 - (void *) ip0);
2318 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2319 vec_len (sl0->rewrite));
2321 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2323 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2324 ip0->hop_limit -= 1;
2326 clib_net_to_host_u16 (ip0->payload_length) +
2327 vec_len (sl0->rewrite);
2328 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2330 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2331 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2332 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2334 ip0->dst_address.as_u64[0] =
2335 (sr0->segments + sr0->segments_left)->as_u64[0];
2336 ip0->dst_address.as_u64[1] =
2337 (sr0->segments + sr0->segments_left)->as_u64[1];
2339 if (ip0 + 1 == (void *) sr0)
2341 sr0->protocol = ip0->protocol;
2342 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2346 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2347 sr0->protocol = ip_ext->next_hdr;
2348 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2351 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2352 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2354 sr_policy_rewrite_trace_t *tr =
2355 vlib_add_trace (vm, node, b0, sizeof (*tr));
2356 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2357 sizeof (tr->src.as_u8));
2358 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2359 sizeof (tr->dst.as_u8));
2364 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2365 n_left_to_next, bi0, next0);
2368 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2371 /* Update counters */
2372 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2373 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2375 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2376 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2378 return from_frame->n_vectors;
2382 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2383 .function = sr_policy_rewrite_insert,
2384 .name = "sr-pl-rewrite-insert",
2385 .vector_size = sizeof (u32),
2386 .format_trace = format_sr_policy_rewrite_trace,
2387 .type = VLIB_NODE_TYPE_INTERNAL,
2388 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2389 .error_strings = sr_policy_rewrite_error_strings,
2390 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2392 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2393 foreach_sr_policy_rewrite_next
2400 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2403 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2404 vlib_frame_t * from_frame)
2406 ip6_sr_main_t *sm = &sr_main;
2407 u32 n_left_from, next_index, *from, *to_next;
2409 from = vlib_frame_vector_args (from_frame);
2410 n_left_from = from_frame->n_vectors;
2412 next_index = node->cached_next_index;
2414 int insert_pkts = 0, bsid_pkts = 0;
2416 while (n_left_from > 0)
2420 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2423 while (n_left_from >= 8 && n_left_to_next >= 4)
2425 u32 bi0, bi1, bi2, bi3;
2426 vlib_buffer_t *b0, *b1, *b2, *b3;
2427 u32 next0, next1, next2, next3;
2428 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2429 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2430 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2431 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2432 u16 new_l0, new_l1, new_l2, new_l3;
2434 /* Prefetch next iteration. */
2436 vlib_buffer_t *p4, *p5, *p6, *p7;
2438 p4 = vlib_get_buffer (vm, from[4]);
2439 p5 = vlib_get_buffer (vm, from[5]);
2440 p6 = vlib_get_buffer (vm, from[6]);
2441 p7 = vlib_get_buffer (vm, from[7]);
2443 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2444 vlib_prefetch_buffer_header (p4, LOAD);
2445 vlib_prefetch_buffer_header (p5, LOAD);
2446 vlib_prefetch_buffer_header (p6, LOAD);
2447 vlib_prefetch_buffer_header (p7, LOAD);
2449 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2450 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2451 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2452 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2455 to_next[0] = bi0 = from[0];
2456 to_next[1] = bi1 = from[1];
2457 to_next[2] = bi2 = from[2];
2458 to_next[3] = bi3 = from[3];
2462 n_left_to_next -= 4;
2464 b0 = vlib_get_buffer (vm, bi0);
2465 b1 = vlib_get_buffer (vm, bi1);
2466 b2 = vlib_get_buffer (vm, bi2);
2467 b3 = vlib_get_buffer (vm, bi3);
2470 pool_elt_at_index (sm->sid_lists,
2471 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2473 pool_elt_at_index (sm->sid_lists,
2474 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2476 pool_elt_at_index (sm->sid_lists,
2477 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2479 pool_elt_at_index (sm->sid_lists,
2480 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2481 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2482 vec_len (sl0->rewrite_bsid));
2483 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2484 vec_len (sl1->rewrite_bsid));
2485 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2486 vec_len (sl2->rewrite_bsid));
2487 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2488 vec_len (sl3->rewrite_bsid));
2490 ip0 = vlib_buffer_get_current (b0);
2491 ip1 = vlib_buffer_get_current (b1);
2492 ip2 = vlib_buffer_get_current (b2);
2493 ip3 = vlib_buffer_get_current (b3);
2495 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2497 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2498 ip6_ext_header_len (ip0 + 1));
2500 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2502 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2504 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2505 ip6_ext_header_len (ip1 + 1));
2507 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2509 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2511 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2512 ip6_ext_header_len (ip2 + 1));
2514 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2516 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2518 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2519 ip6_ext_header_len (ip3 + 1));
2521 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2523 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2524 (void *) sr0 - (void *) ip0);
2525 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2526 (void *) sr1 - (void *) ip1);
2527 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2528 (void *) sr2 - (void *) ip2);
2529 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2530 (void *) sr3 - (void *) ip3);
2532 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2533 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2534 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2535 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2536 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2537 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2538 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2539 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2541 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2542 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2543 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2544 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2546 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2547 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2548 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2549 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2551 ip0->hop_limit -= 1;
2552 ip1->hop_limit -= 1;
2553 ip2->hop_limit -= 1;
2554 ip3->hop_limit -= 1;
2557 clib_net_to_host_u16 (ip0->payload_length) +
2558 vec_len (sl0->rewrite_bsid);
2560 clib_net_to_host_u16 (ip1->payload_length) +
2561 vec_len (sl1->rewrite_bsid);
2563 clib_net_to_host_u16 (ip2->payload_length) +
2564 vec_len (sl2->rewrite_bsid);
2566 clib_net_to_host_u16 (ip3->payload_length) +
2567 vec_len (sl3->rewrite_bsid);
2569 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2570 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2571 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2572 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2574 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2575 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2576 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2577 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2579 ip0->dst_address.as_u64[0] =
2580 (sr0->segments + sr0->segments_left)->as_u64[0];
2581 ip0->dst_address.as_u64[1] =
2582 (sr0->segments + sr0->segments_left)->as_u64[1];
2583 ip1->dst_address.as_u64[0] =
2584 (sr1->segments + sr1->segments_left)->as_u64[0];
2585 ip1->dst_address.as_u64[1] =
2586 (sr1->segments + sr1->segments_left)->as_u64[1];
2587 ip2->dst_address.as_u64[0] =
2588 (sr2->segments + sr2->segments_left)->as_u64[0];
2589 ip2->dst_address.as_u64[1] =
2590 (sr2->segments + sr2->segments_left)->as_u64[1];
2591 ip3->dst_address.as_u64[0] =
2592 (sr3->segments + sr3->segments_left)->as_u64[0];
2593 ip3->dst_address.as_u64[1] =
2594 (sr3->segments + sr3->segments_left)->as_u64[1];
2596 ip6_ext_header_t *ip_ext;
2597 if (ip0 + 1 == (void *) sr0)
2599 sr0->protocol = ip0->protocol;
2600 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2604 ip_ext = (void *) (ip0 + 1);
2605 sr0->protocol = ip_ext->next_hdr;
2606 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2609 if (ip1 + 1 == (void *) sr1)
2611 sr1->protocol = ip1->protocol;
2612 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2616 ip_ext = (void *) (ip2 + 1);
2617 sr2->protocol = ip_ext->next_hdr;
2618 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2621 if (ip2 + 1 == (void *) sr2)
2623 sr2->protocol = ip2->protocol;
2624 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2628 ip_ext = (void *) (ip2 + 1);
2629 sr2->protocol = ip_ext->next_hdr;
2630 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2633 if (ip3 + 1 == (void *) sr3)
2635 sr3->protocol = ip3->protocol;
2636 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2640 ip_ext = (void *) (ip3 + 1);
2641 sr3->protocol = ip_ext->next_hdr;
2642 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2647 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2649 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2651 sr_policy_rewrite_trace_t *tr =
2652 vlib_add_trace (vm, node, b0, sizeof (*tr));
2653 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2654 sizeof (tr->src.as_u8));
2655 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2656 sizeof (tr->dst.as_u8));
2659 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2661 sr_policy_rewrite_trace_t *tr =
2662 vlib_add_trace (vm, node, b1, sizeof (*tr));
2663 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2664 sizeof (tr->src.as_u8));
2665 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2666 sizeof (tr->dst.as_u8));
2669 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2671 sr_policy_rewrite_trace_t *tr =
2672 vlib_add_trace (vm, node, b2, sizeof (*tr));
2673 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2674 sizeof (tr->src.as_u8));
2675 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2676 sizeof (tr->dst.as_u8));
2679 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2681 sr_policy_rewrite_trace_t *tr =
2682 vlib_add_trace (vm, node, b3, sizeof (*tr));
2683 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2684 sizeof (tr->src.as_u8));
2685 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2686 sizeof (tr->dst.as_u8));
2690 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2691 n_left_to_next, bi0, bi1, bi2, bi3,
2692 next0, next1, next2, next3);
2695 /* Single loop for potentially the last three packets */
2696 while (n_left_from > 0 && n_left_to_next > 0)
2700 ip6_header_t *ip0 = 0;
2701 ip6_sr_header_t *sr0 = 0;
2703 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2711 n_left_to_next -= 1;
2713 b0 = vlib_get_buffer (vm, bi0);
2715 pool_elt_at_index (sm->sid_lists,
2716 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2717 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2718 vec_len (sl0->rewrite_bsid));
2720 ip0 = vlib_buffer_get_current (b0);
2722 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2724 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2725 ip6_ext_header_len (ip0 + 1));
2727 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2729 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2730 (void *) sr0 - (void *) ip0);
2731 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2732 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2734 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2736 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2737 ip0->hop_limit -= 1;
2739 clib_net_to_host_u16 (ip0->payload_length) +
2740 vec_len (sl0->rewrite_bsid);
2741 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2743 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2745 ip0->dst_address.as_u64[0] =
2746 (sr0->segments + sr0->segments_left)->as_u64[0];
2747 ip0->dst_address.as_u64[1] =
2748 (sr0->segments + sr0->segments_left)->as_u64[1];
2750 if (ip0 + 1 == (void *) sr0)
2752 sr0->protocol = ip0->protocol;
2753 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2757 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2758 sr0->protocol = ip_ext->next_hdr;
2759 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2762 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2763 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2765 sr_policy_rewrite_trace_t *tr =
2766 vlib_add_trace (vm, node, b0, sizeof (*tr));
2767 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2768 sizeof (tr->src.as_u8));
2769 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2770 sizeof (tr->dst.as_u8));
2775 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2776 n_left_to_next, bi0, next0);
2779 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2782 /* Update counters */
2783 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2784 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2786 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2787 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2789 return from_frame->n_vectors;
2793 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2794 .function = sr_policy_rewrite_b_insert,
2795 .name = "sr-pl-rewrite-b-insert",
2796 .vector_size = sizeof (u32),
2797 .format_trace = format_sr_policy_rewrite_trace,
2798 .type = VLIB_NODE_TYPE_INTERNAL,
2799 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2800 .error_strings = sr_policy_rewrite_error_strings,
2801 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2803 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2804 foreach_sr_policy_rewrite_next
2811 * @brief Function BSID encapsulation
2813 static_always_inline void
2814 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2817 ip6_sr_header_t * sr0, u32 * next0)
2819 ip6_address_t *new_dst0;
2821 if (PREDICT_FALSE (!sr0))
2822 goto error_bsid_encaps;
2824 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2826 if (PREDICT_TRUE (sr0->segments_left != 0))
2828 sr0->segments_left -= 1;
2829 new_dst0 = (ip6_address_t *) (sr0->segments);
2830 new_dst0 += sr0->segments_left;
2831 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2832 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2838 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2839 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2843 * @brief Graph node for applying a SR policy BSID - Encapsulation
2846 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2847 vlib_frame_t * from_frame)
2849 ip6_sr_main_t *sm = &sr_main;
2850 u32 n_left_from, next_index, *from, *to_next;
2852 from = vlib_frame_vector_args (from_frame);
2853 n_left_from = from_frame->n_vectors;
2855 next_index = node->cached_next_index;
2857 int encap_pkts = 0, bsid_pkts = 0;
2859 while (n_left_from > 0)
2863 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2866 while (n_left_from >= 8 && n_left_to_next >= 4)
2868 u32 bi0, bi1, bi2, bi3;
2869 vlib_buffer_t *b0, *b1, *b2, *b3;
2870 u32 next0, next1, next2, next3;
2871 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2872 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2873 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2874 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2875 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2876 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2878 /* Prefetch next iteration. */
2880 vlib_buffer_t *p4, *p5, *p6, *p7;
2882 p4 = vlib_get_buffer (vm, from[4]);
2883 p5 = vlib_get_buffer (vm, from[5]);
2884 p6 = vlib_get_buffer (vm, from[6]);
2885 p7 = vlib_get_buffer (vm, from[7]);
2887 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2888 vlib_prefetch_buffer_header (p4, LOAD);
2889 vlib_prefetch_buffer_header (p5, LOAD);
2890 vlib_prefetch_buffer_header (p6, LOAD);
2891 vlib_prefetch_buffer_header (p7, LOAD);
2893 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2894 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2895 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2896 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2899 to_next[0] = bi0 = from[0];
2900 to_next[1] = bi1 = from[1];
2901 to_next[2] = bi2 = from[2];
2902 to_next[3] = bi3 = from[3];
2906 n_left_to_next -= 4;
2908 b0 = vlib_get_buffer (vm, bi0);
2909 b1 = vlib_get_buffer (vm, bi1);
2910 b2 = vlib_get_buffer (vm, bi2);
2911 b3 = vlib_get_buffer (vm, bi3);
2914 pool_elt_at_index (sm->sid_lists,
2915 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2917 pool_elt_at_index (sm->sid_lists,
2918 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2920 pool_elt_at_index (sm->sid_lists,
2921 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2923 pool_elt_at_index (sm->sid_lists,
2924 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2925 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2926 vec_len (sl0->rewrite));
2927 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2928 vec_len (sl1->rewrite));
2929 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2930 vec_len (sl2->rewrite));
2931 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2932 vec_len (sl3->rewrite));
2934 ip0_encap = vlib_buffer_get_current (b0);
2935 ip1_encap = vlib_buffer_get_current (b1);
2936 ip2_encap = vlib_buffer_get_current (b2);
2937 ip3_encap = vlib_buffer_get_current (b3);
2939 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2940 IP_PROTOCOL_IPV6_ROUTE);
2941 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2942 IP_PROTOCOL_IPV6_ROUTE);
2943 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2944 IP_PROTOCOL_IPV6_ROUTE);
2945 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2946 IP_PROTOCOL_IPV6_ROUTE);
2948 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2949 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2950 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2951 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2953 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2954 sl0->rewrite, vec_len (sl0->rewrite));
2955 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2956 sl1->rewrite, vec_len (sl1->rewrite));
2957 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2958 sl2->rewrite, vec_len (sl2->rewrite));
2959 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2960 sl3->rewrite, vec_len (sl3->rewrite));
2962 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2963 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2964 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2965 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2967 ip0 = vlib_buffer_get_current (b0);
2968 ip1 = vlib_buffer_get_current (b1);
2969 ip2 = vlib_buffer_get_current (b2);
2970 ip3 = vlib_buffer_get_current (b3);
2972 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2973 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2974 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2975 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2977 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2979 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2981 sr_policy_rewrite_trace_t *tr =
2982 vlib_add_trace (vm, node, b0, sizeof (*tr));
2983 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2984 sizeof (tr->src.as_u8));
2985 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2986 sizeof (tr->dst.as_u8));
2989 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2991 sr_policy_rewrite_trace_t *tr =
2992 vlib_add_trace (vm, node, b1, sizeof (*tr));
2993 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2994 sizeof (tr->src.as_u8));
2995 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2996 sizeof (tr->dst.as_u8));
2999 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3001 sr_policy_rewrite_trace_t *tr =
3002 vlib_add_trace (vm, node, b2, sizeof (*tr));
3003 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3004 sizeof (tr->src.as_u8));
3005 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3006 sizeof (tr->dst.as_u8));
3009 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3011 sr_policy_rewrite_trace_t *tr =
3012 vlib_add_trace (vm, node, b3, sizeof (*tr));
3013 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3014 sizeof (tr->src.as_u8));
3015 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3016 sizeof (tr->dst.as_u8));
3021 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3022 n_left_to_next, bi0, bi1, bi2, bi3,
3023 next0, next1, next2, next3);
3026 /* Single loop for potentially the last three packets */
3027 while (n_left_from > 0 && n_left_to_next > 0)
3031 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3032 ip6_ext_header_t *prev0;
3033 ip6_sr_header_t *sr0;
3035 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3042 n_left_to_next -= 1;
3043 b0 = vlib_get_buffer (vm, bi0);
3046 pool_elt_at_index (sm->sid_lists,
3047 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3048 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3049 vec_len (sl0->rewrite));
3051 ip0_encap = vlib_buffer_get_current (b0);
3052 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3053 IP_PROTOCOL_IPV6_ROUTE);
3054 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3056 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3057 sl0->rewrite, vec_len (sl0->rewrite));
3058 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3060 ip0 = vlib_buffer_get_current (b0);
3062 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3064 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3065 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3067 sr_policy_rewrite_trace_t *tr =
3068 vlib_add_trace (vm, node, b0, sizeof (*tr));
3069 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3070 sizeof (tr->src.as_u8));
3071 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3072 sizeof (tr->dst.as_u8));
3076 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3077 n_left_to_next, bi0, next0);
3080 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3083 /* Update counters */
3084 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3085 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3087 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3088 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3091 return from_frame->n_vectors;
3095 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3096 .function = sr_policy_rewrite_b_encaps,
3097 .name = "sr-pl-rewrite-b-encaps",
3098 .vector_size = sizeof (u32),
3099 .format_trace = format_sr_policy_rewrite_trace,
3100 .type = VLIB_NODE_TYPE_INTERNAL,
3101 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3102 .error_strings = sr_policy_rewrite_error_strings,
3103 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3105 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3106 foreach_sr_policy_rewrite_next
3112 /*************************** SR Segment Lists DPOs ****************************/
3114 format_sr_segment_list_dpo (u8 * s, va_list * args)
3116 ip6_sr_main_t *sm = &sr_main;
3117 ip6_address_t *addr;
3120 index_t index = va_arg (*args, index_t);
3121 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3122 s = format (s, "SR: Segment List index:[%d]", index);
3123 s = format (s, "\n\tSegments:");
3125 sl = pool_elt_at_index (sm->sid_lists, index);
3127 s = format (s, "< ");
3128 vec_foreach (addr, sl->segments)
3130 s = format (s, "%U, ", format_ip6_address, addr);
3132 s = format (s, "\b\b > - ");
3133 s = format (s, "Weight: %u", sl->weight);
3138 const static dpo_vft_t sr_policy_rewrite_vft = {
3139 .dv_lock = sr_dpo_lock,
3140 .dv_unlock = sr_dpo_unlock,
3141 .dv_format = format_sr_segment_list_dpo,
3144 const static char *const sr_pr_encaps_ip6_nodes[] = {
3145 "sr-pl-rewrite-encaps",
3149 const static char *const sr_pr_encaps_ip4_nodes[] = {
3150 "sr-pl-rewrite-encaps-v4",
3154 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3155 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3156 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3159 const static char *const sr_pr_insert_ip6_nodes[] = {
3160 "sr-pl-rewrite-insert",
3164 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3165 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3168 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3169 "sr-pl-rewrite-b-insert",
3173 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3174 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3177 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3178 "sr-pl-rewrite-b-encaps",
3182 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3183 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3186 /********************* SR Policy Rewrite initialization ***********************/
3188 * @brief SR Policy Rewrite initialization
3191 sr_policy_rewrite_init (vlib_main_t * vm)
3193 ip6_sr_main_t *sm = &sr_main;
3195 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3196 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3197 sizeof (ip6_address_t));
3199 /* Init SR VPO DPOs type */
3200 sr_pr_encaps_dpo_type =
3201 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3203 sr_pr_insert_dpo_type =
3204 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3206 sr_pr_bsid_encaps_dpo_type =
3207 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3209 sr_pr_bsid_insert_dpo_type =
3210 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3212 /* Register the L2 encaps node used in HW redirect */
3213 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3215 sm->fib_table_ip6 = (u32) ~ 0;
3216 sm->fib_table_ip4 = (u32) ~ 0;
3221 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3225 * fd.io coding-style-patch-verification: ON
3228 * eval: (c-set-style "gnu")