2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
110 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
112 /******************* SR rewrite set encaps IPv6 source addr *******************/
113 /* Note: This is temporal. We don't know whether to follow this path or
114 take the ip address of a loopback interface or even the OIF */
117 sr_set_source (ip6_address_t * address)
119 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
122 static clib_error_t *
123 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
124 vlib_cli_command_t * cmd)
126 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
129 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
132 return clib_error_return (0, "No address specified");
134 return clib_error_return (0, "No address specified");
138 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
139 .path = "set sr encaps source",
140 .short_help = "set sr encaps source addr <ip6_addr>",
141 .function = set_sr_src_command_fn,
145 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
148 sr_set_hop_limit (u8 hop_limit)
150 sr_pr_encaps_hop_limit = hop_limit;
154 sr_get_hop_limit (void)
156 return sr_pr_encaps_hop_limit;
159 static clib_error_t *
160 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
161 vlib_cli_command_t * cmd)
163 int hop_limit = sr_get_hop_limit ();
165 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
166 return clib_error_return (0, "No value specified");
167 if (!unformat (input, "%d", &hop_limit))
168 return clib_error_return (0, "Invalid value");
169 if (hop_limit <= 0 || hop_limit > 255)
170 return clib_error_return (0, "Value out of range [1-255]");
171 sr_pr_encaps_hop_limit = (u8) hop_limit;
176 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
177 .path = "set sr encaps hop-limit",
178 .short_help = "set sr encaps hop-limit <value>",
179 .function = set_sr_hop_limit_command_fn,
183 /*********************** SR rewrite string computation ************************/
185 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
187 * @param sl is a vector of IPv6 addresses composing the Segment List
189 * @return precomputed rewrite string for encapsulation
192 compute_rewrite_encaps (ip6_address_t * sl)
195 ip6_sr_header_t *srh;
196 ip6_address_t *addrp, *this_address;
197 u32 header_length = 0;
201 header_length += IPv6_DEFAULT_HEADER_LENGTH;
202 if (vec_len (sl) > 1)
204 header_length += sizeof (ip6_sr_header_t);
205 header_length += vec_len (sl) * sizeof (ip6_address_t);
208 vec_validate (rs, header_length - 1);
210 iph = (ip6_header_t *) rs;
211 iph->ip_version_traffic_class_and_flow_label =
212 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
213 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
214 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
215 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
216 iph->protocol = IP_PROTOCOL_IPV6;
217 iph->hop_limit = sr_pr_encaps_hop_limit;
219 if (vec_len (sl) > 1)
221 srh = (ip6_sr_header_t *) (iph + 1);
222 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
223 srh->protocol = IP_PROTOCOL_IPV6;
224 srh->type = ROUTING_HEADER_TYPE_SR;
225 srh->segments_left = vec_len (sl) - 1;
226 srh->last_entry = vec_len (sl) - 1;
227 srh->length = ((sizeof (ip6_sr_header_t) +
228 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
231 addrp = srh->segments + vec_len (sl) - 1;
232 vec_foreach (this_address, sl)
234 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
235 sizeof (ip6_address_t));
239 iph->dst_address.as_u64[0] = sl->as_u64[0];
240 iph->dst_address.as_u64[1] = sl->as_u64[1];
245 * @brief SR rewrite string computation for SRH insertion (inline)
247 * @param sl is a vector of IPv6 addresses composing the Segment List
249 * @return precomputed rewrite string for SRH insertion
252 compute_rewrite_insert (ip6_address_t * sl)
254 ip6_sr_header_t *srh;
255 ip6_address_t *addrp, *this_address;
256 u32 header_length = 0;
260 header_length += sizeof (ip6_sr_header_t);
261 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
263 vec_validate (rs, header_length - 1);
265 srh = (ip6_sr_header_t *) rs;
266 srh->type = ROUTING_HEADER_TYPE_SR;
267 srh->segments_left = vec_len (sl);
268 srh->last_entry = vec_len (sl);
269 srh->length = ((sizeof (ip6_sr_header_t) +
270 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
273 addrp = srh->segments + vec_len (sl);
274 vec_foreach (this_address, sl)
276 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
277 sizeof (ip6_address_t));
284 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
286 * @param sl is a vector of IPv6 addresses composing the Segment List
288 * @return precomputed rewrite string for SRH insertion with BSID
291 compute_rewrite_bsid (ip6_address_t * sl)
293 ip6_sr_header_t *srh;
294 ip6_address_t *addrp, *this_address;
295 u32 header_length = 0;
299 header_length += sizeof (ip6_sr_header_t);
300 header_length += vec_len (sl) * sizeof (ip6_address_t);
302 vec_validate (rs, header_length - 1);
304 srh = (ip6_sr_header_t *) rs;
305 srh->type = ROUTING_HEADER_TYPE_SR;
306 srh->segments_left = vec_len (sl) - 1;
307 srh->last_entry = vec_len (sl) - 1;
308 srh->length = ((sizeof (ip6_sr_header_t) +
309 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
312 addrp = srh->segments + vec_len (sl) - 1;
313 vec_foreach (this_address, sl)
315 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
316 sizeof (ip6_address_t));
322 /*************************** SR LB helper functions **************************/
324 * @brief Creates a Segment List and adds it to an SR policy
326 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
327 * not necessarily unique. Hence there might be two Segment List within the
328 * same SR Policy with exactly the same segments and same weight.
330 * @param sr_policy is the SR policy where the SL will be added
331 * @param sl is a vector of IPv6 addresses composing the Segment List
332 * @param weight is the weight of the SegmentList (for load-balancing purposes)
333 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
335 * @return pointer to the just created segment list
337 static inline ip6_sr_sl_t *
338 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
341 ip6_sr_main_t *sm = &sr_main;
342 ip6_sr_sl_t *segment_list;
344 pool_get (sm->sid_lists, segment_list);
345 clib_memset (segment_list, 0, sizeof (*segment_list));
347 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
349 /* Fill in segment list */
350 segment_list->weight =
351 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
352 segment_list->segments = vec_dup (sl);
356 segment_list->rewrite = compute_rewrite_encaps (sl);
357 segment_list->rewrite_bsid = segment_list->rewrite;
361 segment_list->rewrite = compute_rewrite_insert (sl);
362 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
366 dpo_reset (&segment_list->bsid_dpo);
367 dpo_reset (&segment_list->ip6_dpo);
368 dpo_reset (&segment_list->ip4_dpo);
372 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
373 segment_list - sm->sid_lists);
374 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
375 segment_list - sm->sid_lists);
376 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
377 DPO_PROTO_IP6, segment_list - sm->sid_lists);
381 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
382 segment_list - sm->sid_lists);
383 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
384 DPO_PROTO_IP6, segment_list - sm->sid_lists);
391 * @brief Updates the Load Balancer after an SR Policy change
393 * @param sr_policy is the modified SR Policy
396 update_lb (ip6_sr_policy_t * sr_policy)
398 flow_hash_config_t fhc;
400 ip6_sr_sl_t *segment_list;
401 ip6_sr_main_t *sm = &sr_main;
402 load_balance_path_t path;
403 path.path_index = FIB_NODE_INDEX_INVALID;
404 load_balance_path_t *ip4_path_vector = 0;
405 load_balance_path_t *ip6_path_vector = 0;
406 load_balance_path_t *b_path_vector = 0;
408 /* In case LB does not exist, create it */
409 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
412 .fp_proto = FIB_PROTOCOL_IP6,
415 .ip6 = sr_policy->bsid,
419 /* Add FIB entry for BSID */
420 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
423 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
424 load_balance_create (0, DPO_PROTO_IP6, fhc));
426 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
427 load_balance_create (0, DPO_PROTO_IP6, fhc));
429 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
430 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
431 sr_policy->fib_table),
433 FIB_ENTRY_FLAG_EXCLUSIVE,
434 &sr_policy->bsid_dpo);
436 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
439 FIB_ENTRY_FLAG_EXCLUSIVE,
440 &sr_policy->ip6_dpo);
442 if (sr_policy->is_encap)
444 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
445 load_balance_create (0, DPO_PROTO_IP4, fhc));
447 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
450 FIB_ENTRY_FLAG_EXCLUSIVE,
451 &sr_policy->ip4_dpo);
456 /* Create the LB path vector */
457 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
458 vec_foreach (sl_index, sr_policy->segments_lists)
460 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
461 path.path_dpo = segment_list->bsid_dpo;
462 path.path_weight = segment_list->weight;
463 vec_add1 (b_path_vector, path);
464 path.path_dpo = segment_list->ip6_dpo;
465 vec_add1 (ip6_path_vector, path);
466 if (sr_policy->is_encap)
468 path.path_dpo = segment_list->ip4_dpo;
469 vec_add1 (ip4_path_vector, path);
473 /* Update LB multipath */
474 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
475 LOAD_BALANCE_FLAG_NONE);
476 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
477 LOAD_BALANCE_FLAG_NONE);
478 if (sr_policy->is_encap)
479 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
480 LOAD_BALANCE_FLAG_NONE);
483 vec_free (b_path_vector);
484 vec_free (ip6_path_vector);
485 vec_free (ip4_path_vector);
490 * @brief Updates the Replicate DPO after an SR Policy change
492 * @param sr_policy is the modified SR Policy (type spray)
495 update_replicate (ip6_sr_policy_t * sr_policy)
498 ip6_sr_sl_t *segment_list;
499 ip6_sr_main_t *sm = &sr_main;
500 load_balance_path_t path;
501 path.path_index = FIB_NODE_INDEX_INVALID;
502 load_balance_path_t *b_path_vector = 0;
503 load_balance_path_t *ip6_path_vector = 0;
504 load_balance_path_t *ip4_path_vector = 0;
506 /* In case LB does not exist, create it */
507 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
509 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
510 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
512 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
513 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
515 /* Update FIB entry's DPO to point to SR without LB */
517 .fp_proto = FIB_PROTOCOL_IP6,
520 .ip6 = sr_policy->bsid,
523 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
524 sr_policy->fib_table),
526 FIB_ENTRY_FLAG_EXCLUSIVE,
527 &sr_policy->bsid_dpo);
529 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
532 FIB_ENTRY_FLAG_EXCLUSIVE,
533 &sr_policy->ip6_dpo);
535 if (sr_policy->is_encap)
537 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
538 replicate_create (0, DPO_PROTO_IP4));
540 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
543 FIB_ENTRY_FLAG_EXCLUSIVE,
544 &sr_policy->ip4_dpo);
549 /* Create the replicate path vector */
550 path.path_weight = 1;
551 vec_foreach (sl_index, sr_policy->segments_lists)
553 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
554 path.path_dpo = segment_list->bsid_dpo;
555 vec_add1 (b_path_vector, path);
556 path.path_dpo = segment_list->ip6_dpo;
557 vec_add1 (ip6_path_vector, path);
558 if (sr_policy->is_encap)
560 path.path_dpo = segment_list->ip4_dpo;
561 vec_add1 (ip4_path_vector, path);
565 /* Update replicate multipath */
566 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
567 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
568 if (sr_policy->is_encap)
569 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
572 /******************************* SR rewrite API *******************************/
573 /* Three functions for handling sr policies:
577 * All of them are API. CLI function on sr_policy_command_fn */
580 * @brief Create a new SR policy
582 * @param bsid is the bindingSID of the SR Policy
583 * @param segments is a vector of IPv6 address composing the segment list
584 * @param weight is the weight of the sid list. optional.
585 * @param behavior is the behavior of the SR policy. (default//spray)
586 * @param fib_table is the VRF where to install the FIB entry for the BSID
587 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
589 * @return 0 if correct, else error
592 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
593 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
595 ip6_sr_main_t *sm = &sr_main;
596 ip6_sr_policy_t *sr_policy = 0;
599 /* Search for existing keys (BSID) */
600 p = mhash_get (&sm->sr_policies_index_hash, bsid);
603 /* Add SR policy that already exists; complain */
607 /* Search collision in FIB entries */
608 /* Explanation: It might be possible that some other entity has already
609 * created a route for the BSID. This in theory is impossible, but in
610 * practise we could see it. Assert it and scream if needed */
612 .fp_proto = FIB_PROTOCOL_IP6,
619 /* Lookup the FIB index associated to the table selected */
620 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
621 (fib_table != (u32) ~ 0 ? fib_table : 0));
625 /* Lookup whether there exists an entry for the BSID */
626 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
627 if (FIB_NODE_INDEX_INVALID != fei)
628 return -12; //There is an entry for such lookup
630 /* Add an SR policy object */
631 pool_get (sm->sr_policies, sr_policy);
632 clib_memset (sr_policy, 0, sizeof (*sr_policy));
633 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
634 sr_policy->type = behavior;
635 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
636 sr_policy->is_encap = is_encap;
639 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
642 /* Create a segment list and add the index to the SR policy */
643 create_sl (sr_policy, segments, weight, is_encap);
645 /* If FIB doesnt exist, create them */
646 if (sm->fib_table_ip6 == (u32) ~ 0)
648 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
650 "SRv6 steering of IP6 prefixes through BSIDs");
651 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
653 "SRv6 steering of IP4 prefixes through BSIDs");
656 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
657 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
658 update_lb (sr_policy);
659 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
660 update_replicate (sr_policy);
665 * @brief Delete a SR policy
667 * @param bsid is the bindingSID of the SR Policy
668 * @param index is the index of the SR policy
670 * @return 0 if correct, else error
673 sr_policy_del (ip6_address_t * bsid, u32 index)
675 ip6_sr_main_t *sm = &sr_main;
676 ip6_sr_policy_t *sr_policy = 0;
677 ip6_sr_sl_t *segment_list;
683 p = mhash_get (&sm->sr_policies_index_hash, bsid);
685 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
691 sr_policy = pool_elt_at_index (sm->sr_policies, index);
696 /* Remove BindingSID FIB entry */
698 .fp_proto = FIB_PROTOCOL_IP6,
701 .ip6 = sr_policy->bsid,
706 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
707 sr_policy->fib_table),
708 &pfx, FIB_SOURCE_SR);
710 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
712 if (sr_policy->is_encap)
713 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
715 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
717 dpo_reset (&sr_policy->bsid_dpo);
718 dpo_reset (&sr_policy->ip4_dpo);
719 dpo_reset (&sr_policy->ip6_dpo);
722 /* Clean SID Lists */
723 vec_foreach (sl_index, sr_policy->segments_lists)
725 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
726 vec_free (segment_list->segments);
727 vec_free (segment_list->rewrite);
728 if (!sr_policy->is_encap)
729 vec_free (segment_list->rewrite_bsid);
730 pool_put_index (sm->sid_lists, *sl_index);
733 /* Remove SR policy entry */
734 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
735 pool_put (sm->sr_policies, sr_policy);
737 /* If FIB empty unlock it */
738 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
740 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
741 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
742 sm->fib_table_ip6 = (u32) ~ 0;
743 sm->fib_table_ip4 = (u32) ~ 0;
750 * @brief Modify an existing SR policy
752 * The possible modifications are adding a new Segment List, modifying an
753 * existing Segment List (modify the weight only) and delete a given
754 * Segment List from the SR Policy.
756 * @param bsid is the bindingSID of the SR Policy
757 * @param index is the index of the SR policy
758 * @param fib_table is the VRF where to install the FIB entry for the BSID
759 * @param operation is the operation to perform (among the top ones)
760 * @param segments is a vector of IPv6 address composing the segment list
761 * @param sl_index is the index of the Segment List to modify/delete
762 * @param weight is the weight of the sid list. optional.
763 * @param is_encap Mode. Encapsulation or SRH insertion.
765 * @return 0 if correct, else error
768 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
769 u8 operation, ip6_address_t * segments, u32 sl_index,
772 ip6_sr_main_t *sm = &sr_main;
773 ip6_sr_policy_t *sr_policy = 0;
774 ip6_sr_sl_t *segment_list;
775 u32 *sl_index_iterate;
780 p = mhash_get (&sm->sr_policies_index_hash, bsid);
782 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
788 sr_policy = pool_elt_at_index (sm->sr_policies, index);
793 if (operation == 1) /* Add SR List to an existing SR policy */
795 /* Create the new SL */
797 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
799 /* Create a new LB DPO */
800 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
801 update_lb (sr_policy);
802 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
803 update_replicate (sr_policy);
805 else if (operation == 2) /* Delete SR List from an existing SR policy */
807 /* Check that currently there are more than one SID list */
808 if (vec_len (sr_policy->segments_lists) == 1)
811 /* Check that the SR list does exist and is assigned to the sr policy */
812 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
813 if (*sl_index_iterate == sl_index)
816 if (*sl_index_iterate != sl_index)
819 /* Remove the lucky SR list that is being kicked out */
820 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
821 vec_free (segment_list->segments);
822 vec_free (segment_list->rewrite);
823 if (!sr_policy->is_encap)
824 vec_free (segment_list->rewrite_bsid);
825 pool_put_index (sm->sid_lists, sl_index);
826 vec_del1 (sr_policy->segments_lists,
827 sl_index_iterate - sr_policy->segments_lists);
829 /* Create a new LB DPO */
830 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
831 update_lb (sr_policy);
832 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
833 update_replicate (sr_policy);
835 else if (operation == 3) /* Modify the weight of an existing SR List */
837 /* Find the corresponding SL */
838 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
839 if (*sl_index_iterate == sl_index)
842 if (*sl_index_iterate != sl_index)
845 /* Change the weight */
846 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
847 segment_list->weight = weight;
850 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
851 update_lb (sr_policy);
853 else /* Incorrect op. */
860 * @brief CLI for 'sr policies' command family
862 static clib_error_t *
863 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
864 vlib_cli_command_t * cmd)
867 char is_del = 0, is_add = 0, is_mod = 0;
869 ip6_address_t bsid, next_address;
870 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
871 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
872 ip6_address_t *segments = 0, *this_seg;
877 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
879 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
881 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
883 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
886 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
888 else if (!is_add && !policy_set
889 && unformat (input, "index %d", &sr_policy_index))
891 else if (unformat (input, "weight %d", &weight));
893 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
895 vec_add2 (segments, this_seg, 1);
896 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
899 else if (unformat (input, "add sl"))
901 else if (unformat (input, "del sl index %d", &sl_index))
903 else if (unformat (input, "mod sl index %d", &sl_index))
905 else if (fib_table == (u32) ~ 0
906 && unformat (input, "fib-table %d", &fib_table));
907 else if (unformat (input, "encap"))
909 else if (unformat (input, "insert"))
911 else if (unformat (input, "spray"))
917 if (!is_add && !is_mod && !is_del)
918 return clib_error_return (0, "Incorrect CLI");
921 return clib_error_return (0, "No SR policy BSID or index specified");
925 if (vec_len (segments) == 0)
926 return clib_error_return (0, "No Segment List specified");
927 rv = sr_policy_add (&bsid, segments, weight,
928 (is_spray ? SR_POLICY_TYPE_SPRAY :
929 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
933 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
938 return clib_error_return (0, "No SL modification specified");
939 if (operation != 1 && sl_index == (u32) ~ 0)
940 return clib_error_return (0, "No Segment List index specified");
941 if (operation == 1 && vec_len (segments) == 0)
942 return clib_error_return (0, "No Segment List specified");
943 if (operation == 3 && weight == (u32) ~ 0)
944 return clib_error_return (0, "No new weight for the SL specified");
945 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
946 sr_policy_index, fib_table, operation, segments,
958 return clib_error_return (0,
959 "There is already a FIB entry for the BindingSID address.\n"
960 "The SR policy could not be created.");
962 return clib_error_return (0, "The specified FIB table does not exist.");
964 return clib_error_return (0,
965 "The selected SR policy only contains ONE segment list. "
966 "Please remove the SR policy instead");
968 return clib_error_return (0,
969 "Could not delete the segment list. "
970 "It is not associated with that SR policy.");
972 return clib_error_return (0,
973 "Could not modify the segment list. "
974 "The given SL is not associated with such SR policy.");
976 return clib_error_return (0, "BUG: sr policy returns %d", rv);
982 VLIB_CLI_COMMAND (sr_policy_command, static) = {
984 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
985 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
987 "Manipulation of SR policies.\n"
988 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
989 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
990 "Segment Routing policies might be of type encapsulation or srh insertion\n"
991 "Each SR policy will be associated with a unique BindingSID.\n"
992 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
993 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
994 "The add command will create a SR policy with its first segment list (sl)\n"
995 "The mod command allows you to add, remove, or modify the existing segment lists\n"
996 "within an SR policy.\n"
997 "The del command allows you to delete a SR policy along with all its associated\n"
999 .function = sr_policy_command_fn,
1004 * @brief CLI to display onscreen all the SR policies
1006 static clib_error_t *
1007 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1008 vlib_cli_command_t * cmd)
1010 ip6_sr_main_t *sm = &sr_main;
1012 ip6_sr_sl_t *segment_list = 0;
1013 ip6_sr_policy_t *sr_policy = 0;
1014 ip6_sr_policy_t **vec_policies = 0;
1015 ip6_address_t *addr;
1019 vlib_cli_output (vm, "SR policies:");
1022 pool_foreach (sr_policy, sm->sr_policies,
1023 {vec_add1 (vec_policies, sr_policy); } );
1026 vec_foreach_index (i, vec_policies)
1028 sr_policy = vec_policies[i];
1029 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1030 (u32) (sr_policy - sm->sr_policies),
1031 format_ip6_address, &sr_policy->bsid);
1032 vlib_cli_output (vm, "\tBehavior: %s",
1033 (sr_policy->is_encap ? "Encapsulation" :
1035 vlib_cli_output (vm, "\tType: %s",
1037 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1038 vlib_cli_output (vm, "\tFIB table: %u",
1039 (sr_policy->fib_table !=
1040 (u32) ~ 0 ? sr_policy->fib_table : 0));
1041 vlib_cli_output (vm, "\tSegment Lists:");
1042 vec_foreach (sl_index, sr_policy->segments_lists)
1045 s = format (s, "\t[%u].- ", *sl_index);
1046 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1047 s = format (s, "< ");
1048 vec_foreach (addr, segment_list->segments)
1050 s = format (s, "%U, ", format_ip6_address, addr);
1052 s = format (s, "\b\b > ");
1053 s = format (s, "weight: %u", segment_list->weight);
1054 vlib_cli_output (vm, " %s", s);
1056 vlib_cli_output (vm, "-----------");
1062 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1063 .path = "show sr policies",
1064 .short_help = "show sr policies",
1065 .function = show_sr_policies_command_fn,
1069 /*************************** SR rewrite graph node ****************************/
1071 * @brief Trace for the SR Policy Rewrite graph node
1074 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1077 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1078 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1079 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1082 (s, "SR-policy-rewrite: src %U dst %U",
1083 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1089 * @brief IPv6 encapsulation processing as per RFC2473
1091 static_always_inline void
1092 encaps_processing_v6 (vlib_node_runtime_t * node,
1094 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1098 ip0_encap->hop_limit -= 1;
1100 ip0->payload_length + sizeof (ip6_header_t) +
1101 clib_net_to_host_u16 (ip0_encap->payload_length);
1102 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1103 ip0->ip_version_traffic_class_and_flow_label =
1104 ip0_encap->ip_version_traffic_class_and_flow_label;
1108 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1111 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1112 vlib_frame_t * from_frame)
1114 ip6_sr_main_t *sm = &sr_main;
1115 u32 n_left_from, next_index, *from, *to_next;
1117 from = vlib_frame_vector_args (from_frame);
1118 n_left_from = from_frame->n_vectors;
1120 next_index = node->cached_next_index;
1122 int encap_pkts = 0, bsid_pkts = 0;
1124 while (n_left_from > 0)
1128 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1131 while (n_left_from >= 8 && n_left_to_next >= 4)
1133 u32 bi0, bi1, bi2, bi3;
1134 vlib_buffer_t *b0, *b1, *b2, *b3;
1135 u32 next0, next1, next2, next3;
1136 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1137 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1138 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1139 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1141 /* Prefetch next iteration. */
1143 vlib_buffer_t *p4, *p5, *p6, *p7;
1145 p4 = vlib_get_buffer (vm, from[4]);
1146 p5 = vlib_get_buffer (vm, from[5]);
1147 p6 = vlib_get_buffer (vm, from[6]);
1148 p7 = vlib_get_buffer (vm, from[7]);
1150 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1151 vlib_prefetch_buffer_header (p4, LOAD);
1152 vlib_prefetch_buffer_header (p5, LOAD);
1153 vlib_prefetch_buffer_header (p6, LOAD);
1154 vlib_prefetch_buffer_header (p7, LOAD);
1156 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1157 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1158 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1159 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1162 to_next[0] = bi0 = from[0];
1163 to_next[1] = bi1 = from[1];
1164 to_next[2] = bi2 = from[2];
1165 to_next[3] = bi3 = from[3];
1169 n_left_to_next -= 4;
1171 b0 = vlib_get_buffer (vm, bi0);
1172 b1 = vlib_get_buffer (vm, bi1);
1173 b2 = vlib_get_buffer (vm, bi2);
1174 b3 = vlib_get_buffer (vm, bi3);
1177 pool_elt_at_index (sm->sid_lists,
1178 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1180 pool_elt_at_index (sm->sid_lists,
1181 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1183 pool_elt_at_index (sm->sid_lists,
1184 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1186 pool_elt_at_index (sm->sid_lists,
1187 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1189 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1190 vec_len (sl0->rewrite));
1191 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1192 vec_len (sl1->rewrite));
1193 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1194 vec_len (sl2->rewrite));
1195 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1196 vec_len (sl3->rewrite));
1198 ip0_encap = vlib_buffer_get_current (b0);
1199 ip1_encap = vlib_buffer_get_current (b1);
1200 ip2_encap = vlib_buffer_get_current (b2);
1201 ip3_encap = vlib_buffer_get_current (b3);
1203 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1204 sl0->rewrite, vec_len (sl0->rewrite));
1205 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1206 sl1->rewrite, vec_len (sl1->rewrite));
1207 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1208 sl2->rewrite, vec_len (sl2->rewrite));
1209 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1210 sl3->rewrite, vec_len (sl3->rewrite));
1212 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1213 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1214 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1215 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1217 ip0 = vlib_buffer_get_current (b0);
1218 ip1 = vlib_buffer_get_current (b1);
1219 ip2 = vlib_buffer_get_current (b2);
1220 ip3 = vlib_buffer_get_current (b3);
1222 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1223 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1224 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1225 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1227 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1229 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1231 sr_policy_rewrite_trace_t *tr =
1232 vlib_add_trace (vm, node, b0, sizeof (*tr));
1233 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1234 sizeof (tr->src.as_u8));
1235 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1236 sizeof (tr->dst.as_u8));
1239 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1241 sr_policy_rewrite_trace_t *tr =
1242 vlib_add_trace (vm, node, b1, sizeof (*tr));
1243 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1244 sizeof (tr->src.as_u8));
1245 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1246 sizeof (tr->dst.as_u8));
1249 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1251 sr_policy_rewrite_trace_t *tr =
1252 vlib_add_trace (vm, node, b2, sizeof (*tr));
1253 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1254 sizeof (tr->src.as_u8));
1255 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1256 sizeof (tr->dst.as_u8));
1259 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1261 sr_policy_rewrite_trace_t *tr =
1262 vlib_add_trace (vm, node, b3, sizeof (*tr));
1263 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1264 sizeof (tr->src.as_u8));
1265 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1266 sizeof (tr->dst.as_u8));
1271 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1272 n_left_to_next, bi0, bi1, bi2, bi3,
1273 next0, next1, next2, next3);
1276 /* Single loop for potentially the last three packets */
1277 while (n_left_from > 0 && n_left_to_next > 0)
1281 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1283 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1290 n_left_to_next -= 1;
1291 b0 = vlib_get_buffer (vm, bi0);
1294 pool_elt_at_index (sm->sid_lists,
1295 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1296 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1297 vec_len (sl0->rewrite));
1299 ip0_encap = vlib_buffer_get_current (b0);
1301 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1302 sl0->rewrite, vec_len (sl0->rewrite));
1303 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1305 ip0 = vlib_buffer_get_current (b0);
1307 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1309 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1310 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1312 sr_policy_rewrite_trace_t *tr =
1313 vlib_add_trace (vm, node, b0, sizeof (*tr));
1314 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1315 sizeof (tr->src.as_u8));
1316 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1317 sizeof (tr->dst.as_u8));
1321 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1322 n_left_to_next, bi0, next0);
1325 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1328 /* Update counters */
1329 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1330 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1332 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1333 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1336 return from_frame->n_vectors;
1340 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1341 .function = sr_policy_rewrite_encaps,
1342 .name = "sr-pl-rewrite-encaps",
1343 .vector_size = sizeof (u32),
1344 .format_trace = format_sr_policy_rewrite_trace,
1345 .type = VLIB_NODE_TYPE_INTERNAL,
1346 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1347 .error_strings = sr_policy_rewrite_error_strings,
1348 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1350 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1351 foreach_sr_policy_rewrite_next
1358 * @brief IPv4 encapsulation processing as per RFC2473
1360 static_always_inline void
1361 encaps_processing_v4 (vlib_node_runtime_t * node,
1363 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1366 ip6_sr_header_t *sr0;
1370 /* Inner IPv4: Decrement TTL & update checksum */
1371 ip0_encap->ttl -= 1;
1372 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1373 checksum0 += checksum0 >= 0xffff;
1374 ip0_encap->checksum = checksum0;
1376 /* Outer IPv6: Update length, FL, proto */
1377 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1378 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1379 ip0->ip_version_traffic_class_and_flow_label =
1380 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1381 ((ip0_encap->tos & 0xFF) << 20));
1382 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1384 sr0 = (void *) (ip0 + 1);
1385 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1388 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1392 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1395 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1396 vlib_frame_t * from_frame)
1398 ip6_sr_main_t *sm = &sr_main;
1399 u32 n_left_from, next_index, *from, *to_next;
1401 from = vlib_frame_vector_args (from_frame);
1402 n_left_from = from_frame->n_vectors;
1404 next_index = node->cached_next_index;
1406 int encap_pkts = 0, bsid_pkts = 0;
1408 while (n_left_from > 0)
1412 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1415 while (n_left_from >= 8 && n_left_to_next >= 4)
1417 u32 bi0, bi1, bi2, bi3;
1418 vlib_buffer_t *b0, *b1, *b2, *b3;
1419 u32 next0, next1, next2, next3;
1420 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1421 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1422 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1423 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1425 /* Prefetch next iteration. */
1427 vlib_buffer_t *p4, *p5, *p6, *p7;
1429 p4 = vlib_get_buffer (vm, from[4]);
1430 p5 = vlib_get_buffer (vm, from[5]);
1431 p6 = vlib_get_buffer (vm, from[6]);
1432 p7 = vlib_get_buffer (vm, from[7]);
1434 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1435 vlib_prefetch_buffer_header (p4, LOAD);
1436 vlib_prefetch_buffer_header (p5, LOAD);
1437 vlib_prefetch_buffer_header (p6, LOAD);
1438 vlib_prefetch_buffer_header (p7, LOAD);
1440 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1441 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1442 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1443 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1446 to_next[0] = bi0 = from[0];
1447 to_next[1] = bi1 = from[1];
1448 to_next[2] = bi2 = from[2];
1449 to_next[3] = bi3 = from[3];
1453 n_left_to_next -= 4;
1455 b0 = vlib_get_buffer (vm, bi0);
1456 b1 = vlib_get_buffer (vm, bi1);
1457 b2 = vlib_get_buffer (vm, bi2);
1458 b3 = vlib_get_buffer (vm, bi3);
1461 pool_elt_at_index (sm->sid_lists,
1462 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1464 pool_elt_at_index (sm->sid_lists,
1465 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1467 pool_elt_at_index (sm->sid_lists,
1468 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1470 pool_elt_at_index (sm->sid_lists,
1471 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1472 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1473 vec_len (sl0->rewrite));
1474 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1475 vec_len (sl1->rewrite));
1476 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1477 vec_len (sl2->rewrite));
1478 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1479 vec_len (sl3->rewrite));
1481 ip0_encap = vlib_buffer_get_current (b0);
1482 ip1_encap = vlib_buffer_get_current (b1);
1483 ip2_encap = vlib_buffer_get_current (b2);
1484 ip3_encap = vlib_buffer_get_current (b3);
1486 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1487 sl0->rewrite, vec_len (sl0->rewrite));
1488 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1489 sl1->rewrite, vec_len (sl1->rewrite));
1490 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1491 sl2->rewrite, vec_len (sl2->rewrite));
1492 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1493 sl3->rewrite, vec_len (sl3->rewrite));
1495 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1496 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1497 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1498 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1500 ip0 = vlib_buffer_get_current (b0);
1501 ip1 = vlib_buffer_get_current (b1);
1502 ip2 = vlib_buffer_get_current (b2);
1503 ip3 = vlib_buffer_get_current (b3);
1505 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1506 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1507 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1508 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1510 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1512 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1514 sr_policy_rewrite_trace_t *tr =
1515 vlib_add_trace (vm, node, b0, sizeof (*tr));
1516 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1517 sizeof (tr->src.as_u8));
1518 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1519 sizeof (tr->dst.as_u8));
1522 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1524 sr_policy_rewrite_trace_t *tr =
1525 vlib_add_trace (vm, node, b1, sizeof (*tr));
1526 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1527 sizeof (tr->src.as_u8));
1528 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1529 sizeof (tr->dst.as_u8));
1532 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1534 sr_policy_rewrite_trace_t *tr =
1535 vlib_add_trace (vm, node, b2, sizeof (*tr));
1536 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1537 sizeof (tr->src.as_u8));
1538 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1539 sizeof (tr->dst.as_u8));
1542 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1544 sr_policy_rewrite_trace_t *tr =
1545 vlib_add_trace (vm, node, b3, sizeof (*tr));
1546 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1547 sizeof (tr->src.as_u8));
1548 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1549 sizeof (tr->dst.as_u8));
1554 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1555 n_left_to_next, bi0, bi1, bi2, bi3,
1556 next0, next1, next2, next3);
1559 /* Single loop for potentially the last three packets */
1560 while (n_left_from > 0 && n_left_to_next > 0)
1564 ip6_header_t *ip0 = 0;
1565 ip4_header_t *ip0_encap = 0;
1567 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1574 n_left_to_next -= 1;
1575 b0 = vlib_get_buffer (vm, bi0);
1578 pool_elt_at_index (sm->sid_lists,
1579 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1580 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1581 vec_len (sl0->rewrite));
1583 ip0_encap = vlib_buffer_get_current (b0);
1585 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1586 sl0->rewrite, vec_len (sl0->rewrite));
1587 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1589 ip0 = vlib_buffer_get_current (b0);
1591 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1593 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1594 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1596 sr_policy_rewrite_trace_t *tr =
1597 vlib_add_trace (vm, node, b0, sizeof (*tr));
1598 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1599 sizeof (tr->src.as_u8));
1600 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1601 sizeof (tr->dst.as_u8));
1605 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1606 n_left_to_next, bi0, next0);
1609 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1612 /* Update counters */
1613 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1614 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1616 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1617 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1620 return from_frame->n_vectors;
1624 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1625 .function = sr_policy_rewrite_encaps_v4,
1626 .name = "sr-pl-rewrite-encaps-v4",
1627 .vector_size = sizeof (u32),
1628 .format_trace = format_sr_policy_rewrite_trace,
1629 .type = VLIB_NODE_TYPE_INTERNAL,
1630 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1631 .error_strings = sr_policy_rewrite_error_strings,
1632 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1634 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1635 foreach_sr_policy_rewrite_next
1642 ip_flow_hash (void *data)
1644 ip4_header_t *iph = (ip4_header_t *) data;
1646 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1647 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1649 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1655 return (*((u64 *) m) & 0xffffffffffff);
1659 l2_flow_hash (vlib_buffer_t * b0)
1661 ethernet_header_t *eh;
1663 uword is_ip, eh_size;
1666 eh = vlib_buffer_get_current (b0);
1667 eh_type = clib_net_to_host_u16 (eh->type);
1668 eh_size = ethernet_buffer_header_size (b0);
1670 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1672 /* since we have 2 cache lines, use them */
1674 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1678 b = mac_to_u64 ((u8 *) eh->dst_address);
1679 c = mac_to_u64 ((u8 *) eh->src_address);
1680 hash_mix64 (a, b, c);
1686 * @brief Graph node for applying a SR policy into a L2 frame
1689 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1690 vlib_frame_t * from_frame)
1692 ip6_sr_main_t *sm = &sr_main;
1693 u32 n_left_from, next_index, *from, *to_next;
1695 from = vlib_frame_vector_args (from_frame);
1696 n_left_from = from_frame->n_vectors;
1698 next_index = node->cached_next_index;
1700 int encap_pkts = 0, bsid_pkts = 0;
1702 while (n_left_from > 0)
1706 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1709 while (n_left_from >= 8 && n_left_to_next >= 4)
1711 u32 bi0, bi1, bi2, bi3;
1712 vlib_buffer_t *b0, *b1, *b2, *b3;
1713 u32 next0, next1, next2, next3;
1714 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1715 ethernet_header_t *en0, *en1, *en2, *en3;
1716 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1717 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1718 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1719 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1721 /* Prefetch next iteration. */
1723 vlib_buffer_t *p4, *p5, *p6, *p7;
1725 p4 = vlib_get_buffer (vm, from[4]);
1726 p5 = vlib_get_buffer (vm, from[5]);
1727 p6 = vlib_get_buffer (vm, from[6]);
1728 p7 = vlib_get_buffer (vm, from[7]);
1730 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1731 vlib_prefetch_buffer_header (p4, LOAD);
1732 vlib_prefetch_buffer_header (p5, LOAD);
1733 vlib_prefetch_buffer_header (p6, LOAD);
1734 vlib_prefetch_buffer_header (p7, LOAD);
1736 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1737 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1738 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1739 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1742 to_next[0] = bi0 = from[0];
1743 to_next[1] = bi1 = from[1];
1744 to_next[2] = bi2 = from[2];
1745 to_next[3] = bi3 = from[3];
1749 n_left_to_next -= 4;
1751 b0 = vlib_get_buffer (vm, bi0);
1752 b1 = vlib_get_buffer (vm, bi1);
1753 b2 = vlib_get_buffer (vm, bi2);
1754 b3 = vlib_get_buffer (vm, bi3);
1756 sp0 = pool_elt_at_index (sm->sr_policies,
1757 sm->sw_iface_sr_policies[vnet_buffer
1761 sp1 = pool_elt_at_index (sm->sr_policies,
1762 sm->sw_iface_sr_policies[vnet_buffer
1766 sp2 = pool_elt_at_index (sm->sr_policies,
1767 sm->sw_iface_sr_policies[vnet_buffer
1771 sp3 = pool_elt_at_index (sm->sr_policies,
1772 sm->sw_iface_sr_policies[vnet_buffer
1776 if (vec_len (sp0->segments_lists) == 1)
1777 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1780 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1781 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1782 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1783 (vec_len (sp0->segments_lists) - 1))];
1786 if (vec_len (sp1->segments_lists) == 1)
1787 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1790 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1791 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1792 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1793 (vec_len (sp1->segments_lists) - 1))];
1796 if (vec_len (sp2->segments_lists) == 1)
1797 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1800 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1801 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1802 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1803 (vec_len (sp2->segments_lists) - 1))];
1806 if (vec_len (sp3->segments_lists) == 1)
1807 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1810 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1811 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1812 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1813 (vec_len (sp3->segments_lists) - 1))];
1817 pool_elt_at_index (sm->sid_lists,
1818 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1820 pool_elt_at_index (sm->sid_lists,
1821 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1823 pool_elt_at_index (sm->sid_lists,
1824 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1826 pool_elt_at_index (sm->sid_lists,
1827 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1829 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1830 vec_len (sl0->rewrite));
1831 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1832 vec_len (sl1->rewrite));
1833 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1834 vec_len (sl2->rewrite));
1835 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1836 vec_len (sl3->rewrite));
1838 en0 = vlib_buffer_get_current (b0);
1839 en1 = vlib_buffer_get_current (b1);
1840 en2 = vlib_buffer_get_current (b2);
1841 en3 = vlib_buffer_get_current (b3);
1843 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1844 sl0->rewrite, vec_len (sl0->rewrite));
1845 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1846 sl1->rewrite, vec_len (sl1->rewrite));
1847 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1848 sl2->rewrite, vec_len (sl2->rewrite));
1849 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1850 sl3->rewrite, vec_len (sl3->rewrite));
1852 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1853 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1854 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1855 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1857 ip0 = vlib_buffer_get_current (b0);
1858 ip1 = vlib_buffer_get_current (b1);
1859 ip2 = vlib_buffer_get_current (b2);
1860 ip3 = vlib_buffer_get_current (b3);
1862 ip0->payload_length =
1863 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1864 ip1->payload_length =
1865 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1866 ip2->payload_length =
1867 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1868 ip3->payload_length =
1869 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1871 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1873 sr0 = (void *) (ip0 + 1);
1874 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1877 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1879 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1881 sr1 = (void *) (ip1 + 1);
1882 sr1->protocol = IP_PROTOCOL_IP6_NONXT;
1885 ip1->protocol = IP_PROTOCOL_IP6_NONXT;
1887 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1889 sr2 = (void *) (ip2 + 1);
1890 sr2->protocol = IP_PROTOCOL_IP6_NONXT;
1893 ip2->protocol = IP_PROTOCOL_IP6_NONXT;
1895 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1897 sr3 = (void *) (ip3 + 1);
1898 sr3->protocol = IP_PROTOCOL_IP6_NONXT;
1901 ip3->protocol = IP_PROTOCOL_IP6_NONXT;
1903 /* Which Traffic class and flow label do I set ? */
1904 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1906 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1908 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1910 sr_policy_rewrite_trace_t *tr =
1911 vlib_add_trace (vm, node, b0, sizeof (*tr));
1912 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1913 sizeof (tr->src.as_u8));
1914 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1915 sizeof (tr->dst.as_u8));
1918 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1920 sr_policy_rewrite_trace_t *tr =
1921 vlib_add_trace (vm, node, b1, sizeof (*tr));
1922 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1923 sizeof (tr->src.as_u8));
1924 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1925 sizeof (tr->dst.as_u8));
1928 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1930 sr_policy_rewrite_trace_t *tr =
1931 vlib_add_trace (vm, node, b2, sizeof (*tr));
1932 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1933 sizeof (tr->src.as_u8));
1934 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1935 sizeof (tr->dst.as_u8));
1938 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1940 sr_policy_rewrite_trace_t *tr =
1941 vlib_add_trace (vm, node, b3, sizeof (*tr));
1942 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1943 sizeof (tr->src.as_u8));
1944 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1945 sizeof (tr->dst.as_u8));
1950 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1951 n_left_to_next, bi0, bi1, bi2, bi3,
1952 next0, next1, next2, next3);
1955 /* Single loop for potentially the last three packets */
1956 while (n_left_from > 0 && n_left_to_next > 0)
1960 ip6_header_t *ip0 = 0;
1961 ip6_sr_header_t *sr0;
1962 ethernet_header_t *en0;
1963 ip6_sr_policy_t *sp0;
1965 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1972 n_left_to_next -= 1;
1973 b0 = vlib_get_buffer (vm, bi0);
1975 /* Find the SR policy */
1976 sp0 = pool_elt_at_index (sm->sr_policies,
1977 sm->sw_iface_sr_policies[vnet_buffer
1981 /* In case there is more than one SL, LB among them */
1982 if (vec_len (sp0->segments_lists) == 1)
1983 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1986 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1987 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1988 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1989 (vec_len (sp0->segments_lists) - 1))];
1992 pool_elt_at_index (sm->sid_lists,
1993 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1994 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1995 vec_len (sl0->rewrite));
1997 en0 = vlib_buffer_get_current (b0);
1999 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2000 sl0->rewrite, vec_len (sl0->rewrite));
2002 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2004 ip0 = vlib_buffer_get_current (b0);
2006 ip0->payload_length =
2007 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2009 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2011 sr0 = (void *) (ip0 + 1);
2012 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
2015 ip0->protocol = IP_PROTOCOL_IP6_NONXT;
2017 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2018 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2020 sr_policy_rewrite_trace_t *tr =
2021 vlib_add_trace (vm, node, b0, sizeof (*tr));
2022 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2023 sizeof (tr->src.as_u8));
2024 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2025 sizeof (tr->dst.as_u8));
2029 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2030 n_left_to_next, bi0, next0);
2033 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2036 /* Update counters */
2037 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2038 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2040 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2041 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2044 return from_frame->n_vectors;
2048 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2049 .function = sr_policy_rewrite_encaps_l2,
2050 .name = "sr-pl-rewrite-encaps-l2",
2051 .vector_size = sizeof (u32),
2052 .format_trace = format_sr_policy_rewrite_trace,
2053 .type = VLIB_NODE_TYPE_INTERNAL,
2054 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2055 .error_strings = sr_policy_rewrite_error_strings,
2056 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2058 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2059 foreach_sr_policy_rewrite_next
2066 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2069 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2070 vlib_frame_t * from_frame)
2072 ip6_sr_main_t *sm = &sr_main;
2073 u32 n_left_from, next_index, *from, *to_next;
2075 from = vlib_frame_vector_args (from_frame);
2076 n_left_from = from_frame->n_vectors;
2078 next_index = node->cached_next_index;
2080 int insert_pkts = 0, bsid_pkts = 0;
2082 while (n_left_from > 0)
2086 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2089 while (n_left_from >= 8 && n_left_to_next >= 4)
2091 u32 bi0, bi1, bi2, bi3;
2092 vlib_buffer_t *b0, *b1, *b2, *b3;
2093 u32 next0, next1, next2, next3;
2094 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2095 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2096 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2097 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2098 u16 new_l0, new_l1, new_l2, new_l3;
2100 /* Prefetch next iteration. */
2102 vlib_buffer_t *p4, *p5, *p6, *p7;
2104 p4 = vlib_get_buffer (vm, from[4]);
2105 p5 = vlib_get_buffer (vm, from[5]);
2106 p6 = vlib_get_buffer (vm, from[6]);
2107 p7 = vlib_get_buffer (vm, from[7]);
2109 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2110 vlib_prefetch_buffer_header (p4, LOAD);
2111 vlib_prefetch_buffer_header (p5, LOAD);
2112 vlib_prefetch_buffer_header (p6, LOAD);
2113 vlib_prefetch_buffer_header (p7, LOAD);
2115 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2116 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2117 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2118 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2121 to_next[0] = bi0 = from[0];
2122 to_next[1] = bi1 = from[1];
2123 to_next[2] = bi2 = from[2];
2124 to_next[3] = bi3 = from[3];
2128 n_left_to_next -= 4;
2130 b0 = vlib_get_buffer (vm, bi0);
2131 b1 = vlib_get_buffer (vm, bi1);
2132 b2 = vlib_get_buffer (vm, bi2);
2133 b3 = vlib_get_buffer (vm, bi3);
2136 pool_elt_at_index (sm->sid_lists,
2137 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2139 pool_elt_at_index (sm->sid_lists,
2140 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2142 pool_elt_at_index (sm->sid_lists,
2143 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2145 pool_elt_at_index (sm->sid_lists,
2146 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2147 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2148 vec_len (sl0->rewrite));
2149 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2150 vec_len (sl1->rewrite));
2151 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2152 vec_len (sl2->rewrite));
2153 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2154 vec_len (sl3->rewrite));
2156 ip0 = vlib_buffer_get_current (b0);
2157 ip1 = vlib_buffer_get_current (b1);
2158 ip2 = vlib_buffer_get_current (b2);
2159 ip3 = vlib_buffer_get_current (b3);
2161 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2163 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2164 ip6_ext_header_len (ip0 + 1));
2166 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2168 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2170 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2171 ip6_ext_header_len (ip1 + 1));
2173 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2175 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2177 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2178 ip6_ext_header_len (ip2 + 1));
2180 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2182 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2184 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2185 ip6_ext_header_len (ip3 + 1));
2187 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2189 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2190 (void *) sr0 - (void *) ip0);
2191 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2192 (void *) sr1 - (void *) ip1);
2193 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2194 (void *) sr2 - (void *) ip2);
2195 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2196 (void *) sr3 - (void *) ip3);
2198 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2199 sl0->rewrite, vec_len (sl0->rewrite));
2200 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2201 sl1->rewrite, vec_len (sl1->rewrite));
2202 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2203 sl2->rewrite, vec_len (sl2->rewrite));
2204 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2205 sl3->rewrite, vec_len (sl3->rewrite));
2207 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2208 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2209 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2210 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2212 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2213 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2214 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2215 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2217 ip0->hop_limit -= 1;
2218 ip1->hop_limit -= 1;
2219 ip2->hop_limit -= 1;
2220 ip3->hop_limit -= 1;
2223 clib_net_to_host_u16 (ip0->payload_length) +
2224 vec_len (sl0->rewrite);
2226 clib_net_to_host_u16 (ip1->payload_length) +
2227 vec_len (sl1->rewrite);
2229 clib_net_to_host_u16 (ip2->payload_length) +
2230 vec_len (sl2->rewrite);
2232 clib_net_to_host_u16 (ip3->payload_length) +
2233 vec_len (sl3->rewrite);
2235 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2236 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2237 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2238 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2240 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2241 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2242 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2243 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2245 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2246 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2247 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2248 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2249 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2250 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2251 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2252 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2254 ip0->dst_address.as_u64[0] =
2255 (sr0->segments + sr0->segments_left)->as_u64[0];
2256 ip0->dst_address.as_u64[1] =
2257 (sr0->segments + sr0->segments_left)->as_u64[1];
2258 ip1->dst_address.as_u64[0] =
2259 (sr1->segments + sr1->segments_left)->as_u64[0];
2260 ip1->dst_address.as_u64[1] =
2261 (sr1->segments + sr1->segments_left)->as_u64[1];
2262 ip2->dst_address.as_u64[0] =
2263 (sr2->segments + sr2->segments_left)->as_u64[0];
2264 ip2->dst_address.as_u64[1] =
2265 (sr2->segments + sr2->segments_left)->as_u64[1];
2266 ip3->dst_address.as_u64[0] =
2267 (sr3->segments + sr3->segments_left)->as_u64[0];
2268 ip3->dst_address.as_u64[1] =
2269 (sr3->segments + sr3->segments_left)->as_u64[1];
2271 ip6_ext_header_t *ip_ext;
2272 if (ip0 + 1 == (void *) sr0)
2274 sr0->protocol = ip0->protocol;
2275 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2279 ip_ext = (void *) (ip0 + 1);
2280 sr0->protocol = ip_ext->next_hdr;
2281 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2284 if (ip1 + 1 == (void *) sr1)
2286 sr1->protocol = ip1->protocol;
2287 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2291 ip_ext = (void *) (ip2 + 1);
2292 sr2->protocol = ip_ext->next_hdr;
2293 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2296 if (ip2 + 1 == (void *) sr2)
2298 sr2->protocol = ip2->protocol;
2299 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2303 ip_ext = (void *) (ip2 + 1);
2304 sr2->protocol = ip_ext->next_hdr;
2305 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2308 if (ip3 + 1 == (void *) sr3)
2310 sr3->protocol = ip3->protocol;
2311 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2315 ip_ext = (void *) (ip3 + 1);
2316 sr3->protocol = ip_ext->next_hdr;
2317 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2322 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2324 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2326 sr_policy_rewrite_trace_t *tr =
2327 vlib_add_trace (vm, node, b0, sizeof (*tr));
2328 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2329 sizeof (tr->src.as_u8));
2330 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2331 sizeof (tr->dst.as_u8));
2334 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2336 sr_policy_rewrite_trace_t *tr =
2337 vlib_add_trace (vm, node, b1, sizeof (*tr));
2338 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2339 sizeof (tr->src.as_u8));
2340 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2341 sizeof (tr->dst.as_u8));
2344 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2346 sr_policy_rewrite_trace_t *tr =
2347 vlib_add_trace (vm, node, b2, sizeof (*tr));
2348 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2349 sizeof (tr->src.as_u8));
2350 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2351 sizeof (tr->dst.as_u8));
2354 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2356 sr_policy_rewrite_trace_t *tr =
2357 vlib_add_trace (vm, node, b3, sizeof (*tr));
2358 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2359 sizeof (tr->src.as_u8));
2360 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2361 sizeof (tr->dst.as_u8));
2365 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2366 n_left_to_next, bi0, bi1, bi2, bi3,
2367 next0, next1, next2, next3);
2370 /* Single loop for potentially the last three packets */
2371 while (n_left_from > 0 && n_left_to_next > 0)
2375 ip6_header_t *ip0 = 0;
2376 ip6_sr_header_t *sr0 = 0;
2378 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2386 n_left_to_next -= 1;
2388 b0 = vlib_get_buffer (vm, bi0);
2390 pool_elt_at_index (sm->sid_lists,
2391 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2392 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2393 vec_len (sl0->rewrite));
2395 ip0 = vlib_buffer_get_current (b0);
2397 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2399 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2400 ip6_ext_header_len (ip0 + 1));
2402 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2404 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2405 (void *) sr0 - (void *) ip0);
2406 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2407 sl0->rewrite, vec_len (sl0->rewrite));
2409 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2411 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2412 ip0->hop_limit -= 1;
2414 clib_net_to_host_u16 (ip0->payload_length) +
2415 vec_len (sl0->rewrite);
2416 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2418 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2419 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2420 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2422 ip0->dst_address.as_u64[0] =
2423 (sr0->segments + sr0->segments_left)->as_u64[0];
2424 ip0->dst_address.as_u64[1] =
2425 (sr0->segments + sr0->segments_left)->as_u64[1];
2427 if (ip0 + 1 == (void *) sr0)
2429 sr0->protocol = ip0->protocol;
2430 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2434 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2435 sr0->protocol = ip_ext->next_hdr;
2436 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2439 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2440 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2442 sr_policy_rewrite_trace_t *tr =
2443 vlib_add_trace (vm, node, b0, sizeof (*tr));
2444 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2445 sizeof (tr->src.as_u8));
2446 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2447 sizeof (tr->dst.as_u8));
2452 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2453 n_left_to_next, bi0, next0);
2456 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2459 /* Update counters */
2460 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2461 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2463 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2464 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2466 return from_frame->n_vectors;
2470 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2471 .function = sr_policy_rewrite_insert,
2472 .name = "sr-pl-rewrite-insert",
2473 .vector_size = sizeof (u32),
2474 .format_trace = format_sr_policy_rewrite_trace,
2475 .type = VLIB_NODE_TYPE_INTERNAL,
2476 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2477 .error_strings = sr_policy_rewrite_error_strings,
2478 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2480 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2481 foreach_sr_policy_rewrite_next
2488 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2491 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2492 vlib_frame_t * from_frame)
2494 ip6_sr_main_t *sm = &sr_main;
2495 u32 n_left_from, next_index, *from, *to_next;
2497 from = vlib_frame_vector_args (from_frame);
2498 n_left_from = from_frame->n_vectors;
2500 next_index = node->cached_next_index;
2502 int insert_pkts = 0, bsid_pkts = 0;
2504 while (n_left_from > 0)
2508 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2511 while (n_left_from >= 8 && n_left_to_next >= 4)
2513 u32 bi0, bi1, bi2, bi3;
2514 vlib_buffer_t *b0, *b1, *b2, *b3;
2515 u32 next0, next1, next2, next3;
2516 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2517 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2518 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2519 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2520 u16 new_l0, new_l1, new_l2, new_l3;
2522 /* Prefetch next iteration. */
2524 vlib_buffer_t *p4, *p5, *p6, *p7;
2526 p4 = vlib_get_buffer (vm, from[4]);
2527 p5 = vlib_get_buffer (vm, from[5]);
2528 p6 = vlib_get_buffer (vm, from[6]);
2529 p7 = vlib_get_buffer (vm, from[7]);
2531 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2532 vlib_prefetch_buffer_header (p4, LOAD);
2533 vlib_prefetch_buffer_header (p5, LOAD);
2534 vlib_prefetch_buffer_header (p6, LOAD);
2535 vlib_prefetch_buffer_header (p7, LOAD);
2537 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2538 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2539 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2540 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2543 to_next[0] = bi0 = from[0];
2544 to_next[1] = bi1 = from[1];
2545 to_next[2] = bi2 = from[2];
2546 to_next[3] = bi3 = from[3];
2550 n_left_to_next -= 4;
2552 b0 = vlib_get_buffer (vm, bi0);
2553 b1 = vlib_get_buffer (vm, bi1);
2554 b2 = vlib_get_buffer (vm, bi2);
2555 b3 = vlib_get_buffer (vm, bi3);
2558 pool_elt_at_index (sm->sid_lists,
2559 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2561 pool_elt_at_index (sm->sid_lists,
2562 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2564 pool_elt_at_index (sm->sid_lists,
2565 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2567 pool_elt_at_index (sm->sid_lists,
2568 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2569 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2570 vec_len (sl0->rewrite_bsid));
2571 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2572 vec_len (sl1->rewrite_bsid));
2573 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2574 vec_len (sl2->rewrite_bsid));
2575 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2576 vec_len (sl3->rewrite_bsid));
2578 ip0 = vlib_buffer_get_current (b0);
2579 ip1 = vlib_buffer_get_current (b1);
2580 ip2 = vlib_buffer_get_current (b2);
2581 ip3 = vlib_buffer_get_current (b3);
2583 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2585 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2586 ip6_ext_header_len (ip0 + 1));
2588 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2590 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2592 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2593 ip6_ext_header_len (ip1 + 1));
2595 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2597 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2599 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2600 ip6_ext_header_len (ip2 + 1));
2602 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2604 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2606 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2607 ip6_ext_header_len (ip3 + 1));
2609 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2611 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2612 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2613 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2614 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2615 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2616 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2617 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2618 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2620 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2621 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2622 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2623 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2624 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2625 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2626 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2627 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2629 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2630 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2631 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2632 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2634 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2635 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2636 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2637 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2639 ip0->hop_limit -= 1;
2640 ip1->hop_limit -= 1;
2641 ip2->hop_limit -= 1;
2642 ip3->hop_limit -= 1;
2645 clib_net_to_host_u16 (ip0->payload_length) +
2646 vec_len (sl0->rewrite_bsid);
2648 clib_net_to_host_u16 (ip1->payload_length) +
2649 vec_len (sl1->rewrite_bsid);
2651 clib_net_to_host_u16 (ip2->payload_length) +
2652 vec_len (sl2->rewrite_bsid);
2654 clib_net_to_host_u16 (ip3->payload_length) +
2655 vec_len (sl3->rewrite_bsid);
2657 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2658 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2659 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2660 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2662 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2663 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2664 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2665 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2667 ip0->dst_address.as_u64[0] =
2668 (sr0->segments + sr0->segments_left)->as_u64[0];
2669 ip0->dst_address.as_u64[1] =
2670 (sr0->segments + sr0->segments_left)->as_u64[1];
2671 ip1->dst_address.as_u64[0] =
2672 (sr1->segments + sr1->segments_left)->as_u64[0];
2673 ip1->dst_address.as_u64[1] =
2674 (sr1->segments + sr1->segments_left)->as_u64[1];
2675 ip2->dst_address.as_u64[0] =
2676 (sr2->segments + sr2->segments_left)->as_u64[0];
2677 ip2->dst_address.as_u64[1] =
2678 (sr2->segments + sr2->segments_left)->as_u64[1];
2679 ip3->dst_address.as_u64[0] =
2680 (sr3->segments + sr3->segments_left)->as_u64[0];
2681 ip3->dst_address.as_u64[1] =
2682 (sr3->segments + sr3->segments_left)->as_u64[1];
2684 ip6_ext_header_t *ip_ext;
2685 if (ip0 + 1 == (void *) sr0)
2687 sr0->protocol = ip0->protocol;
2688 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2692 ip_ext = (void *) (ip0 + 1);
2693 sr0->protocol = ip_ext->next_hdr;
2694 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2697 if (ip1 + 1 == (void *) sr1)
2699 sr1->protocol = ip1->protocol;
2700 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2704 ip_ext = (void *) (ip2 + 1);
2705 sr2->protocol = ip_ext->next_hdr;
2706 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2709 if (ip2 + 1 == (void *) sr2)
2711 sr2->protocol = ip2->protocol;
2712 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2716 ip_ext = (void *) (ip2 + 1);
2717 sr2->protocol = ip_ext->next_hdr;
2718 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2721 if (ip3 + 1 == (void *) sr3)
2723 sr3->protocol = ip3->protocol;
2724 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2728 ip_ext = (void *) (ip3 + 1);
2729 sr3->protocol = ip_ext->next_hdr;
2730 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2735 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2737 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2739 sr_policy_rewrite_trace_t *tr =
2740 vlib_add_trace (vm, node, b0, sizeof (*tr));
2741 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2742 sizeof (tr->src.as_u8));
2743 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2744 sizeof (tr->dst.as_u8));
2747 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2749 sr_policy_rewrite_trace_t *tr =
2750 vlib_add_trace (vm, node, b1, sizeof (*tr));
2751 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2752 sizeof (tr->src.as_u8));
2753 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2754 sizeof (tr->dst.as_u8));
2757 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2759 sr_policy_rewrite_trace_t *tr =
2760 vlib_add_trace (vm, node, b2, sizeof (*tr));
2761 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2762 sizeof (tr->src.as_u8));
2763 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2764 sizeof (tr->dst.as_u8));
2767 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2769 sr_policy_rewrite_trace_t *tr =
2770 vlib_add_trace (vm, node, b3, sizeof (*tr));
2771 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2772 sizeof (tr->src.as_u8));
2773 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2774 sizeof (tr->dst.as_u8));
2778 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2779 n_left_to_next, bi0, bi1, bi2, bi3,
2780 next0, next1, next2, next3);
2783 /* Single loop for potentially the last three packets */
2784 while (n_left_from > 0 && n_left_to_next > 0)
2788 ip6_header_t *ip0 = 0;
2789 ip6_sr_header_t *sr0 = 0;
2791 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2799 n_left_to_next -= 1;
2801 b0 = vlib_get_buffer (vm, bi0);
2803 pool_elt_at_index (sm->sid_lists,
2804 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2805 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2806 vec_len (sl0->rewrite_bsid));
2808 ip0 = vlib_buffer_get_current (b0);
2810 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2812 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2813 ip6_ext_header_len (ip0 + 1));
2815 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2817 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2818 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2819 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2820 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2822 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2824 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2825 ip0->hop_limit -= 1;
2827 clib_net_to_host_u16 (ip0->payload_length) +
2828 vec_len (sl0->rewrite_bsid);
2829 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2831 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2833 ip0->dst_address.as_u64[0] =
2834 (sr0->segments + sr0->segments_left)->as_u64[0];
2835 ip0->dst_address.as_u64[1] =
2836 (sr0->segments + sr0->segments_left)->as_u64[1];
2838 if (ip0 + 1 == (void *) sr0)
2840 sr0->protocol = ip0->protocol;
2841 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2845 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2846 sr0->protocol = ip_ext->next_hdr;
2847 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2850 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2851 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2853 sr_policy_rewrite_trace_t *tr =
2854 vlib_add_trace (vm, node, b0, sizeof (*tr));
2855 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2856 sizeof (tr->src.as_u8));
2857 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2858 sizeof (tr->dst.as_u8));
2863 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2864 n_left_to_next, bi0, next0);
2867 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2870 /* Update counters */
2871 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2872 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2874 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2875 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2877 return from_frame->n_vectors;
2881 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2882 .function = sr_policy_rewrite_b_insert,
2883 .name = "sr-pl-rewrite-b-insert",
2884 .vector_size = sizeof (u32),
2885 .format_trace = format_sr_policy_rewrite_trace,
2886 .type = VLIB_NODE_TYPE_INTERNAL,
2887 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2888 .error_strings = sr_policy_rewrite_error_strings,
2889 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2891 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2892 foreach_sr_policy_rewrite_next
2899 * @brief Function BSID encapsulation
2901 static_always_inline void
2902 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2905 ip6_sr_header_t * sr0, u32 * next0)
2907 ip6_address_t *new_dst0;
2909 if (PREDICT_FALSE (!sr0))
2910 goto error_bsid_encaps;
2912 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2914 if (PREDICT_TRUE (sr0->segments_left != 0))
2916 sr0->segments_left -= 1;
2917 new_dst0 = (ip6_address_t *) (sr0->segments);
2918 new_dst0 += sr0->segments_left;
2919 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2920 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2926 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2927 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2931 * @brief Graph node for applying a SR policy BSID - Encapsulation
2934 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2935 vlib_frame_t * from_frame)
2937 ip6_sr_main_t *sm = &sr_main;
2938 u32 n_left_from, next_index, *from, *to_next;
2940 from = vlib_frame_vector_args (from_frame);
2941 n_left_from = from_frame->n_vectors;
2943 next_index = node->cached_next_index;
2945 int encap_pkts = 0, bsid_pkts = 0;
2947 while (n_left_from > 0)
2951 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2954 while (n_left_from >= 8 && n_left_to_next >= 4)
2956 u32 bi0, bi1, bi2, bi3;
2957 vlib_buffer_t *b0, *b1, *b2, *b3;
2958 u32 next0, next1, next2, next3;
2959 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2960 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2961 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2962 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2963 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2965 /* Prefetch next iteration. */
2967 vlib_buffer_t *p4, *p5, *p6, *p7;
2969 p4 = vlib_get_buffer (vm, from[4]);
2970 p5 = vlib_get_buffer (vm, from[5]);
2971 p6 = vlib_get_buffer (vm, from[6]);
2972 p7 = vlib_get_buffer (vm, from[7]);
2974 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2975 vlib_prefetch_buffer_header (p4, LOAD);
2976 vlib_prefetch_buffer_header (p5, LOAD);
2977 vlib_prefetch_buffer_header (p6, LOAD);
2978 vlib_prefetch_buffer_header (p7, LOAD);
2980 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2981 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2982 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2983 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2986 to_next[0] = bi0 = from[0];
2987 to_next[1] = bi1 = from[1];
2988 to_next[2] = bi2 = from[2];
2989 to_next[3] = bi3 = from[3];
2993 n_left_to_next -= 4;
2995 b0 = vlib_get_buffer (vm, bi0);
2996 b1 = vlib_get_buffer (vm, bi1);
2997 b2 = vlib_get_buffer (vm, bi2);
2998 b3 = vlib_get_buffer (vm, bi3);
3001 pool_elt_at_index (sm->sid_lists,
3002 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3004 pool_elt_at_index (sm->sid_lists,
3005 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3007 pool_elt_at_index (sm->sid_lists,
3008 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3010 pool_elt_at_index (sm->sid_lists,
3011 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3012 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3013 vec_len (sl0->rewrite));
3014 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3015 vec_len (sl1->rewrite));
3016 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3017 vec_len (sl2->rewrite));
3018 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3019 vec_len (sl3->rewrite));
3021 ip0_encap = vlib_buffer_get_current (b0);
3022 ip1_encap = vlib_buffer_get_current (b1);
3023 ip2_encap = vlib_buffer_get_current (b2);
3024 ip3_encap = vlib_buffer_get_current (b3);
3027 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3030 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3033 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3036 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3039 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3040 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3041 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3042 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3044 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3045 sl0->rewrite, vec_len (sl0->rewrite));
3046 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3047 sl1->rewrite, vec_len (sl1->rewrite));
3048 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3049 sl2->rewrite, vec_len (sl2->rewrite));
3050 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3051 sl3->rewrite, vec_len (sl3->rewrite));
3053 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3054 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3055 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3056 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3058 ip0 = vlib_buffer_get_current (b0);
3059 ip1 = vlib_buffer_get_current (b1);
3060 ip2 = vlib_buffer_get_current (b2);
3061 ip3 = vlib_buffer_get_current (b3);
3063 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3064 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3065 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3066 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3068 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3070 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3072 sr_policy_rewrite_trace_t *tr =
3073 vlib_add_trace (vm, node, b0, sizeof (*tr));
3074 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3075 sizeof (tr->src.as_u8));
3076 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3077 sizeof (tr->dst.as_u8));
3080 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3082 sr_policy_rewrite_trace_t *tr =
3083 vlib_add_trace (vm, node, b1, sizeof (*tr));
3084 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3085 sizeof (tr->src.as_u8));
3086 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3087 sizeof (tr->dst.as_u8));
3090 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3092 sr_policy_rewrite_trace_t *tr =
3093 vlib_add_trace (vm, node, b2, sizeof (*tr));
3094 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3095 sizeof (tr->src.as_u8));
3096 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3097 sizeof (tr->dst.as_u8));
3100 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3102 sr_policy_rewrite_trace_t *tr =
3103 vlib_add_trace (vm, node, b3, sizeof (*tr));
3104 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3105 sizeof (tr->src.as_u8));
3106 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3107 sizeof (tr->dst.as_u8));
3112 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3113 n_left_to_next, bi0, bi1, bi2, bi3,
3114 next0, next1, next2, next3);
3117 /* Single loop for potentially the last three packets */
3118 while (n_left_from > 0 && n_left_to_next > 0)
3122 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3123 ip6_sr_header_t *sr0;
3125 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3132 n_left_to_next -= 1;
3133 b0 = vlib_get_buffer (vm, bi0);
3136 pool_elt_at_index (sm->sid_lists,
3137 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3138 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3139 vec_len (sl0->rewrite));
3141 ip0_encap = vlib_buffer_get_current (b0);
3143 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3145 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3147 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3148 sl0->rewrite, vec_len (sl0->rewrite));
3149 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3151 ip0 = vlib_buffer_get_current (b0);
3153 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3155 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3156 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3158 sr_policy_rewrite_trace_t *tr =
3159 vlib_add_trace (vm, node, b0, sizeof (*tr));
3160 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3161 sizeof (tr->src.as_u8));
3162 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3163 sizeof (tr->dst.as_u8));
3167 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3168 n_left_to_next, bi0, next0);
3171 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3174 /* Update counters */
3175 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3176 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3178 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3179 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3182 return from_frame->n_vectors;
3186 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3187 .function = sr_policy_rewrite_b_encaps,
3188 .name = "sr-pl-rewrite-b-encaps",
3189 .vector_size = sizeof (u32),
3190 .format_trace = format_sr_policy_rewrite_trace,
3191 .type = VLIB_NODE_TYPE_INTERNAL,
3192 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3193 .error_strings = sr_policy_rewrite_error_strings,
3194 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3196 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3197 foreach_sr_policy_rewrite_next
3203 /*************************** SR Segment Lists DPOs ****************************/
3205 format_sr_segment_list_dpo (u8 * s, va_list * args)
3207 ip6_sr_main_t *sm = &sr_main;
3208 ip6_address_t *addr;
3211 index_t index = va_arg (*args, index_t);
3212 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3213 s = format (s, "SR: Segment List index:[%d]", index);
3214 s = format (s, "\n\tSegments:");
3216 sl = pool_elt_at_index (sm->sid_lists, index);
3218 s = format (s, "< ");
3219 vec_foreach (addr, sl->segments)
3221 s = format (s, "%U, ", format_ip6_address, addr);
3223 s = format (s, "\b\b > - ");
3224 s = format (s, "Weight: %u", sl->weight);
3229 const static dpo_vft_t sr_policy_rewrite_vft = {
3230 .dv_lock = sr_dpo_lock,
3231 .dv_unlock = sr_dpo_unlock,
3232 .dv_format = format_sr_segment_list_dpo,
3235 const static char *const sr_pr_encaps_ip6_nodes[] = {
3236 "sr-pl-rewrite-encaps",
3240 const static char *const sr_pr_encaps_ip4_nodes[] = {
3241 "sr-pl-rewrite-encaps-v4",
3245 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3246 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3247 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3250 const static char *const sr_pr_insert_ip6_nodes[] = {
3251 "sr-pl-rewrite-insert",
3255 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3256 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3259 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3260 "sr-pl-rewrite-b-insert",
3264 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3265 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3268 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3269 "sr-pl-rewrite-b-encaps",
3273 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3274 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3277 /********************* SR Policy Rewrite initialization ***********************/
3279 * @brief SR Policy Rewrite initialization
3282 sr_policy_rewrite_init (vlib_main_t * vm)
3284 ip6_sr_main_t *sm = &sr_main;
3286 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3287 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3288 sizeof (ip6_address_t));
3290 /* Init SR VPO DPOs type */
3291 sr_pr_encaps_dpo_type =
3292 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3294 sr_pr_insert_dpo_type =
3295 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3297 sr_pr_bsid_encaps_dpo_type =
3298 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3300 sr_pr_bsid_insert_dpo_type =
3301 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3303 /* Register the L2 encaps node used in HW redirect */
3304 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3306 sm->fib_table_ip6 = (u32) ~ 0;
3307 sm->fib_table_ip4 = (u32) ~ 0;
3312 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3316 * fd.io coding-style-patch-verification: ON
3319 * eval: (c-set-style "gnu")