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/ip4_inlines.h>
45 #include <vnet/ip/ip6_inlines.h>
46 #include <vnet/srv6/sr_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));
123 sr_get_encaps_source ()
125 return &sr_pr_encaps_src;
128 static clib_error_t *
129 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130 vlib_cli_command_t * cmd)
132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
135 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
138 return clib_error_return (0, "No address specified");
140 return clib_error_return (0, "No address specified");
144 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145 .path = "set sr encaps source",
146 .short_help = "set sr encaps source addr <ip6_addr>",
147 .function = set_sr_src_command_fn,
151 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
154 sr_set_hop_limit (u8 hop_limit)
156 sr_pr_encaps_hop_limit = hop_limit;
160 sr_get_hop_limit (void)
162 return sr_pr_encaps_hop_limit;
165 static clib_error_t *
166 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167 vlib_cli_command_t * cmd)
169 int hop_limit = sr_get_hop_limit ();
171 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172 return clib_error_return (0, "No value specified");
173 if (!unformat (input, "%d", &hop_limit))
174 return clib_error_return (0, "Invalid value");
175 if (hop_limit <= 0 || hop_limit > 255)
176 return clib_error_return (0, "Value out of range [1-255]");
177 sr_pr_encaps_hop_limit = (u8) hop_limit;
182 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183 .path = "set sr encaps hop-limit",
184 .short_help = "set sr encaps hop-limit <value>",
185 .function = set_sr_hop_limit_command_fn,
189 /*********************** SR rewrite string computation ************************/
191 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
193 * @param sl is a vector of IPv6 addresses composing the Segment List
195 * @return precomputed rewrite string for encapsulation
198 compute_rewrite_encaps (ip6_address_t * sl)
201 ip6_sr_header_t *srh;
202 ip6_address_t *addrp, *this_address;
203 u32 header_length = 0;
207 header_length += IPv6_DEFAULT_HEADER_LENGTH;
208 if (vec_len (sl) > 1)
210 header_length += sizeof (ip6_sr_header_t);
211 header_length += vec_len (sl) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 iph = (ip6_header_t *) rs;
217 iph->ip_version_traffic_class_and_flow_label =
218 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
219 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
220 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
221 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
222 iph->protocol = IP_PROTOCOL_IPV6;
223 iph->hop_limit = sr_pr_encaps_hop_limit;
225 if (vec_len (sl) > 1)
227 srh = (ip6_sr_header_t *) (iph + 1);
228 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
229 srh->protocol = IP_PROTOCOL_IPV6;
230 srh->type = ROUTING_HEADER_TYPE_SR;
231 srh->segments_left = vec_len (sl) - 1;
232 srh->last_entry = vec_len (sl) - 1;
233 srh->length = ((sizeof (ip6_sr_header_t) +
234 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
237 addrp = srh->segments + vec_len (sl) - 1;
238 vec_foreach (this_address, sl)
240 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
241 sizeof (ip6_address_t));
245 iph->dst_address.as_u64[0] = sl->as_u64[0];
246 iph->dst_address.as_u64[1] = sl->as_u64[1];
251 * @brief SR rewrite string computation for SRH insertion (inline)
253 * @param sl is a vector of IPv6 addresses composing the Segment List
255 * @return precomputed rewrite string for SRH insertion
258 compute_rewrite_insert (ip6_address_t * sl)
260 ip6_sr_header_t *srh;
261 ip6_address_t *addrp, *this_address;
262 u32 header_length = 0;
266 header_length += sizeof (ip6_sr_header_t);
267 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
269 vec_validate (rs, header_length - 1);
271 srh = (ip6_sr_header_t *) rs;
272 srh->type = ROUTING_HEADER_TYPE_SR;
273 srh->segments_left = vec_len (sl);
274 srh->last_entry = vec_len (sl);
275 srh->length = ((sizeof (ip6_sr_header_t) +
276 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
279 addrp = srh->segments + vec_len (sl);
280 vec_foreach (this_address, sl)
282 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
283 sizeof (ip6_address_t));
290 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
292 * @param sl is a vector of IPv6 addresses composing the Segment List
294 * @return precomputed rewrite string for SRH insertion with BSID
297 compute_rewrite_bsid (ip6_address_t * sl)
299 ip6_sr_header_t *srh;
300 ip6_address_t *addrp, *this_address;
301 u32 header_length = 0;
305 header_length += sizeof (ip6_sr_header_t);
306 header_length += vec_len (sl) * sizeof (ip6_address_t);
308 vec_validate (rs, header_length - 1);
310 srh = (ip6_sr_header_t *) rs;
311 srh->type = ROUTING_HEADER_TYPE_SR;
312 srh->segments_left = vec_len (sl) - 1;
313 srh->last_entry = vec_len (sl) - 1;
314 srh->length = ((sizeof (ip6_sr_header_t) +
315 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
318 addrp = srh->segments + vec_len (sl) - 1;
319 vec_foreach (this_address, sl)
321 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
322 sizeof (ip6_address_t));
328 /*************************** SR LB helper functions **************************/
330 * @brief Creates a Segment List and adds it to an SR policy
332 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
333 * not necessarily unique. Hence there might be two Segment List within the
334 * same SR Policy with exactly the same segments and same weight.
336 * @param sr_policy is the SR policy where the SL will be added
337 * @param sl is a vector of IPv6 addresses composing the Segment List
338 * @param weight is the weight of the SegmentList (for load-balancing purposes)
339 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
341 * @return pointer to the just created segment list
343 static inline ip6_sr_sl_t *
344 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
347 ip6_sr_main_t *sm = &sr_main;
348 ip6_sr_sl_t *segment_list;
349 sr_policy_fn_registration_t *plugin = 0;
351 pool_get (sm->sid_lists, segment_list);
352 clib_memset (segment_list, 0, sizeof (*segment_list));
354 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
356 /* Fill in segment list */
357 segment_list->weight =
358 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
360 segment_list->segments = vec_dup (sl);
364 segment_list->rewrite = compute_rewrite_encaps (sl);
365 segment_list->rewrite_bsid = segment_list->rewrite;
369 segment_list->rewrite = compute_rewrite_insert (sl);
370 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
373 if (sr_policy->plugin)
376 pool_elt_at_index (sm->policy_plugin_functions,
377 sr_policy->plugin - SR_BEHAVIOR_LAST);
379 segment_list->plugin = sr_policy->plugin;
380 segment_list->plugin_mem = sr_policy->plugin_mem;
382 plugin->creation (sr_policy);
386 dpo_reset (&segment_list->bsid_dpo);
387 dpo_reset (&segment_list->ip6_dpo);
388 dpo_reset (&segment_list->ip4_dpo);
392 if (!sr_policy->plugin)
394 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
395 DPO_PROTO_IP6, segment_list - sm->sid_lists);
396 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
397 DPO_PROTO_IP4, segment_list - sm->sid_lists);
398 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
399 DPO_PROTO_IP6, segment_list - sm->sid_lists);
403 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
404 segment_list - sm->sid_lists);
405 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
406 segment_list - sm->sid_lists);
407 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
408 segment_list - sm->sid_lists);
413 if (!sr_policy->plugin)
415 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
416 DPO_PROTO_IP6, segment_list - sm->sid_lists);
417 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
418 DPO_PROTO_IP6, segment_list - sm->sid_lists);
422 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
423 segment_list - sm->sid_lists);
424 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
425 segment_list - sm->sid_lists);
433 * @brief Updates the Load Balancer after an SR Policy change
435 * @param sr_policy is the modified SR Policy
438 update_lb (ip6_sr_policy_t * sr_policy)
440 flow_hash_config_t fhc;
442 ip6_sr_sl_t *segment_list;
443 ip6_sr_main_t *sm = &sr_main;
444 load_balance_path_t path;
445 path.path_index = FIB_NODE_INDEX_INVALID;
446 load_balance_path_t *ip4_path_vector = 0;
447 load_balance_path_t *ip6_path_vector = 0;
448 load_balance_path_t *b_path_vector = 0;
450 /* In case LB does not exist, create it */
451 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
454 .fp_proto = FIB_PROTOCOL_IP6,
457 .ip6 = sr_policy->bsid,
461 /* Add FIB entry for BSID */
462 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
465 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
466 load_balance_create (0, DPO_PROTO_IP6, fhc));
468 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
469 load_balance_create (0, DPO_PROTO_IP6, fhc));
471 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
484 if (sr_policy->is_encap)
486 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
487 load_balance_create (0, DPO_PROTO_IP4, fhc));
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
498 /* Create the LB path vector */
499 vec_foreach (sl_index, sr_policy->segments_lists)
501 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
502 path.path_dpo = segment_list->bsid_dpo;
503 path.path_weight = segment_list->weight;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
514 /* Update LB multipath */
515 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
516 LOAD_BALANCE_FLAG_NONE);
517 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
518 LOAD_BALANCE_FLAG_NONE);
519 if (sr_policy->is_encap)
520 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
521 LOAD_BALANCE_FLAG_NONE);
524 vec_free (b_path_vector);
525 vec_free (ip6_path_vector);
526 vec_free (ip4_path_vector);
530 * @brief Updates the Replicate DPO after an SR Policy change
532 * @param sr_policy is the modified SR Policy (type spray)
535 update_replicate (ip6_sr_policy_t * sr_policy)
538 ip6_sr_sl_t *segment_list;
539 ip6_sr_main_t *sm = &sr_main;
540 load_balance_path_t path;
541 path.path_index = FIB_NODE_INDEX_INVALID;
542 load_balance_path_t *b_path_vector = 0;
543 load_balance_path_t *ip6_path_vector = 0;
544 load_balance_path_t *ip4_path_vector = 0;
546 /* In case LB does not exist, create it */
547 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
549 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
550 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
552 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
553 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
555 /* Update FIB entry's DPO to point to SR without LB */
557 .fp_proto = FIB_PROTOCOL_IP6,
560 .ip6 = sr_policy->bsid,
563 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
564 sr_policy->fib_table),
566 FIB_ENTRY_FLAG_EXCLUSIVE,
567 &sr_policy->bsid_dpo);
569 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
572 FIB_ENTRY_FLAG_EXCLUSIVE,
573 &sr_policy->ip6_dpo);
575 if (sr_policy->is_encap)
577 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
578 replicate_create (0, DPO_PROTO_IP4));
580 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
583 FIB_ENTRY_FLAG_EXCLUSIVE,
584 &sr_policy->ip4_dpo);
589 /* Create the replicate path vector */
590 path.path_weight = 1;
591 vec_foreach (sl_index, sr_policy->segments_lists)
593 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
594 path.path_dpo = segment_list->bsid_dpo;
595 vec_add1 (b_path_vector, path);
596 path.path_dpo = segment_list->ip6_dpo;
597 vec_add1 (ip6_path_vector, path);
598 if (sr_policy->is_encap)
600 path.path_dpo = segment_list->ip4_dpo;
601 vec_add1 (ip4_path_vector, path);
605 /* Update replicate multipath */
606 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
607 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
608 if (sr_policy->is_encap)
609 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
612 /******************************* SR rewrite API *******************************/
613 /* Three functions for handling sr policies:
617 * All of them are API. CLI function on sr_policy_command_fn */
620 * @brief Create a new SR policy
622 * @param bsid is the bindingSID of the SR Policy
623 * @param segments is a vector of IPv6 address composing the segment list
624 * @param weight is the weight of the sid list. optional.
625 * @param behavior is the behavior of the SR policy. (default//spray)
626 * @param fib_table is the VRF where to install the FIB entry for the BSID
627 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
629 * @return 0 if correct, else error
632 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
633 u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
634 u16 plugin, void *ls_plugin_mem)
636 ip6_sr_main_t *sm = &sr_main;
637 ip6_sr_policy_t *sr_policy = 0;
640 /* Search for existing keys (BSID) */
641 p = mhash_get (&sm->sr_policies_index_hash, bsid);
644 /* Add SR policy that already exists; complain */
648 /* Search collision in FIB entries */
649 /* Explanation: It might be possible that some other entity has already
650 * created a route for the BSID. This in theory is impossible, but in
651 * practise we could see it. Assert it and scream if needed */
653 .fp_proto = FIB_PROTOCOL_IP6,
660 /* Lookup the FIB index associated to the table selected */
661 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
662 (fib_table != (u32) ~ 0 ? fib_table : 0));
666 /* Lookup whether there exists an entry for the BSID */
667 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
668 if (FIB_NODE_INDEX_INVALID != fei)
669 return -12; //There is an entry for such lookup
671 /* Add an SR policy object */
672 pool_get (sm->sr_policies, sr_policy);
673 clib_memset (sr_policy, 0, sizeof (*sr_policy));
674 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
675 sr_policy->type = behavior;
676 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
677 sr_policy->is_encap = is_encap;
681 sr_policy->plugin = plugin;
682 sr_policy->plugin_mem = ls_plugin_mem;
686 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
689 /* Create a segment list and add the index to the SR policy */
690 create_sl (sr_policy, segments, weight, is_encap);
692 /* If FIB doesnt exist, create them */
693 if (sm->fib_table_ip6 == (u32) ~ 0)
695 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
697 "SRv6 steering of IP6 prefixes through BSIDs");
698 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
700 "SRv6 steering of IP4 prefixes through BSIDs");
703 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
704 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
705 update_lb (sr_policy);
706 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
707 update_replicate (sr_policy);
712 * @brief Delete a SR policy
714 * @param bsid is the bindingSID of the SR Policy
715 * @param index is the index of the SR policy
717 * @return 0 if correct, else error
720 sr_policy_del (ip6_address_t * bsid, u32 index)
722 ip6_sr_main_t *sm = &sr_main;
723 ip6_sr_policy_t *sr_policy = 0;
724 ip6_sr_sl_t *segment_list;
730 p = mhash_get (&sm->sr_policies_index_hash, bsid);
732 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
738 sr_policy = pool_elt_at_index (sm->sr_policies, index);
743 /* Remove BindingSID FIB entry */
745 .fp_proto = FIB_PROTOCOL_IP6,
748 .ip6 = sr_policy->bsid,
753 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
754 sr_policy->fib_table),
755 &pfx, FIB_SOURCE_SR);
757 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
759 if (sr_policy->is_encap)
760 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
762 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
764 dpo_reset (&sr_policy->bsid_dpo);
765 dpo_reset (&sr_policy->ip4_dpo);
766 dpo_reset (&sr_policy->ip6_dpo);
769 /* Clean SID Lists */
770 vec_foreach (sl_index, sr_policy->segments_lists)
772 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
773 vec_free (segment_list->segments);
774 vec_free (segment_list->rewrite);
775 if (!sr_policy->is_encap)
776 vec_free (segment_list->rewrite_bsid);
777 pool_put_index (sm->sid_lists, *sl_index);
780 if (sr_policy->plugin)
782 sr_policy_fn_registration_t *plugin = 0;
785 pool_elt_at_index (sm->policy_plugin_functions,
786 sr_policy->plugin - SR_BEHAVIOR_LAST);
788 plugin->removal (sr_policy);
789 sr_policy->plugin = 0;
790 sr_policy->plugin_mem = NULL;
793 /* Remove SR policy entry */
794 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
795 pool_put (sm->sr_policies, sr_policy);
797 /* If FIB empty unlock it */
798 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
800 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
801 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
802 sm->fib_table_ip6 = (u32) ~ 0;
803 sm->fib_table_ip4 = (u32) ~ 0;
810 * @brief Modify an existing SR policy
812 * The possible modifications are adding a new Segment List, modifying an
813 * existing Segment List (modify the weight only) and delete a given
814 * Segment List from the SR Policy.
816 * @param bsid is the bindingSID of the SR Policy
817 * @param index is the index of the SR policy
818 * @param fib_table is the VRF where to install the FIB entry for the BSID
819 * @param operation is the operation to perform (among the top ones)
820 * @param segments is a vector of IPv6 address composing the segment list
821 * @param sl_index is the index of the Segment List to modify/delete
822 * @param weight is the weight of the sid list. optional.
823 * @param is_encap Mode. Encapsulation or SRH insertion.
825 * @return 0 if correct, else error
828 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
829 u8 operation, ip6_address_t * segments, u32 sl_index,
832 ip6_sr_main_t *sm = &sr_main;
833 ip6_sr_policy_t *sr_policy = 0;
834 ip6_sr_sl_t *segment_list;
835 u32 *sl_index_iterate;
840 p = mhash_get (&sm->sr_policies_index_hash, bsid);
842 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
848 sr_policy = pool_elt_at_index (sm->sr_policies, index);
853 if (operation == 1) /* Add SR List to an existing SR policy */
855 /* Create the new SL */
857 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
859 /* Create a new LB DPO */
860 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
861 update_lb (sr_policy);
862 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
863 update_replicate (sr_policy);
865 else if (operation == 2) /* Delete SR List from an existing SR policy */
867 /* Check that currently there are more than one SID list */
868 if (vec_len (sr_policy->segments_lists) == 1)
871 /* Check that the SR list does exist and is assigned to the sr policy */
872 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
873 if (*sl_index_iterate == sl_index)
876 if (*sl_index_iterate != sl_index)
879 /* Remove the lucky SR list that is being kicked out */
880 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
881 vec_free (segment_list->segments);
882 vec_free (segment_list->rewrite);
883 if (!sr_policy->is_encap)
884 vec_free (segment_list->rewrite_bsid);
885 pool_put_index (sm->sid_lists, sl_index);
886 vec_del1 (sr_policy->segments_lists,
887 sl_index_iterate - sr_policy->segments_lists);
889 /* Create a new LB DPO */
890 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
891 update_lb (sr_policy);
892 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
893 update_replicate (sr_policy);
895 else if (operation == 3) /* Modify the weight of an existing SR List */
897 /* Find the corresponding SL */
898 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
899 if (*sl_index_iterate == sl_index)
902 if (*sl_index_iterate != sl_index)
905 /* Change the weight */
906 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
907 segment_list->weight = weight;
910 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
911 update_lb (sr_policy);
913 else /* Incorrect op. */
920 * @brief CLI for 'sr policies' command family
922 static clib_error_t *
923 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
924 vlib_cli_command_t * cmd)
926 ip6_sr_main_t *sm = &sr_main;
928 char is_del = 0, is_add = 0, is_mod = 0;
930 ip6_address_t bsid, next_address;
931 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
932 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
933 ip6_address_t *segments = 0, *this_seg;
938 void *ls_plugin_mem = 0;
940 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
942 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
944 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
946 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
949 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
951 else if (!is_add && !policy_set
952 && unformat (input, "index %d", &sr_policy_index))
954 else if (unformat (input, "weight %d", &weight));
956 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
958 vec_add2 (segments, this_seg, 1);
959 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
962 else if (unformat (input, "add sl"))
964 else if (unformat (input, "del sl index %d", &sl_index))
966 else if (unformat (input, "mod sl index %d", &sl_index))
968 else if (fib_table == (u32) ~ 0
969 && unformat (input, "fib-table %d", &fib_table));
970 else if (unformat (input, "encap"))
972 else if (unformat (input, "insert"))
974 else if (unformat (input, "spray"))
976 else if (!behavior && unformat (input, "behavior"))
978 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
979 sr_policy_fn_registration_t **plugin_it = 0;
982 pool_foreach (plugin, sm->policy_plugin_functions)
984 vec_add1 (vec_plugins, plugin);
988 vec_foreach (plugin_it, vec_plugins)
991 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
993 behavior = (*plugin_it)->sr_policy_function_number;
1000 return clib_error_return (0, "Invalid behavior");
1007 if (!is_add && !is_mod && !is_del)
1008 return clib_error_return (0, "Incorrect CLI");
1011 return clib_error_return (0, "No SR policy BSID or index specified");
1015 if (behavior && vec_len (segments) == 0)
1017 vec_add2 (segments, this_seg, 1);
1018 clib_memset (this_seg, 0, sizeof (*this_seg));
1021 if (vec_len (segments) == 0)
1022 return clib_error_return (0, "No Segment List specified");
1024 rv = sr_policy_add (&bsid, segments, weight,
1025 (is_spray ? SR_POLICY_TYPE_SPRAY :
1026 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1027 behavior, ls_plugin_mem);
1029 vec_free (segments);
1032 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1037 return clib_error_return (0, "No SL modification specified");
1038 if (operation != 1 && sl_index == (u32) ~ 0)
1039 return clib_error_return (0, "No Segment List index specified");
1040 if (operation == 1 && vec_len (segments) == 0)
1041 return clib_error_return (0, "No Segment List specified");
1042 if (operation == 3 && weight == (u32) ~ 0)
1043 return clib_error_return (0, "No new weight for the SL specified");
1045 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1046 sr_policy_index, fib_table, operation, segments,
1050 vec_free (segments);
1060 return clib_error_return (0,
1061 "There is already a FIB entry for the BindingSID address.\n"
1062 "The SR policy could not be created.");
1064 return clib_error_return (0, "The specified FIB table does not exist.");
1066 return clib_error_return (0,
1067 "The selected SR policy only contains ONE segment list. "
1068 "Please remove the SR policy instead");
1070 return clib_error_return (0,
1071 "Could not delete the segment list. "
1072 "It is not associated with that SR policy.");
1074 return clib_error_return (0,
1075 "Could not modify the segment list. "
1076 "The given SL is not associated with such SR policy.");
1078 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1084 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1085 .path = "sr policy",
1086 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1087 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1089 "Manipulation of SR policies.\n"
1090 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1091 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1092 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1093 "Each SR policy will be associated with a unique BindingSID.\n"
1094 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1095 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1096 "The add command will create a SR policy with its first segment list (sl)\n"
1097 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1098 "within an SR policy.\n"
1099 "The del command allows you to delete a SR policy along with all its associated\n"
1101 .function = sr_policy_command_fn,
1106 * @brief CLI to display onscreen all the SR policies
1108 static clib_error_t *
1109 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1110 vlib_cli_command_t * cmd)
1112 ip6_sr_main_t *sm = &sr_main;
1114 ip6_sr_sl_t *segment_list = 0;
1115 ip6_sr_policy_t *sr_policy = 0;
1116 ip6_sr_policy_t **vec_policies = 0;
1117 ip6_address_t *addr;
1121 vlib_cli_output (vm, "SR policies:");
1124 pool_foreach (sr_policy, sm->sr_policies)
1125 {vec_add1 (vec_policies, sr_policy); }
1128 vec_foreach_index (i, vec_policies)
1130 sr_policy = vec_policies[i];
1131 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1132 (u32) (sr_policy - sm->sr_policies),
1133 format_ip6_address, &sr_policy->bsid);
1134 vlib_cli_output (vm, "\tBehavior: %s",
1135 (sr_policy->is_encap ? "Encapsulation" :
1137 vlib_cli_output (vm, "\tType: %s",
1139 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1140 vlib_cli_output (vm, "\tFIB table: %u",
1141 (sr_policy->fib_table !=
1142 (u32) ~ 0 ? sr_policy->fib_table : 0));
1143 vlib_cli_output (vm, "\tSegment Lists:");
1144 vec_foreach (sl_index, sr_policy->segments_lists)
1147 s = format (s, "\t[%u].- ", *sl_index);
1148 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1149 s = format (s, "< ");
1150 vec_foreach (addr, segment_list->segments)
1152 s = format (s, "%U, ", format_ip6_address, addr);
1154 s = format (s, "\b\b > ");
1155 s = format (s, "weight: %u", segment_list->weight);
1156 vlib_cli_output (vm, " %v", s);
1158 vlib_cli_output (vm, "-----------");
1164 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1165 .path = "show sr policies",
1166 .short_help = "show sr policies",
1167 .function = show_sr_policies_command_fn,
1172 * @brief CLI to display onscreen the SR encaps source addr
1174 static clib_error_t *
1175 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1176 vlib_cli_command_t * cmd)
1178 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1179 sr_get_encaps_source ());
1185 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1186 .path = "show sr encaps source addr",
1187 .short_help = "show sr encaps source addr",
1188 .function = show_sr_encaps_source_command_fn,
1193 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1195 static clib_error_t *
1196 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1197 unformat_input_t * input,
1198 vlib_cli_command_t * cmd)
1200 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1206 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1207 .path = "show sr encaps hop-limit",
1208 .short_help = "show sr encaps hop-limit",
1209 .function = show_sr_encaps_hop_limit_command_fn,
1213 /*************************** SR rewrite graph node ****************************/
1215 * @brief Trace for the SR Policy Rewrite graph node
1218 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1221 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1222 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1223 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1226 (s, "SR-policy-rewrite: src %U dst %U",
1227 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1233 * @brief IPv6 encapsulation processing as per RFC2473
1235 static_always_inline void
1236 encaps_processing_v6 (vlib_node_runtime_t * node,
1238 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1243 ip0_encap->hop_limit -= 1;
1245 ip0->payload_length + sizeof (ip6_header_t) +
1246 clib_net_to_host_u16 (ip0_encap->payload_length);
1247 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1249 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1250 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1252 (clib_net_to_host_u32 (
1253 ip0_encap->ip_version_traffic_class_and_flow_label) &
1255 (flow_label & 0x0000ffff));
1259 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1262 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1263 vlib_frame_t * from_frame)
1265 ip6_sr_main_t *sm = &sr_main;
1266 u32 n_left_from, next_index, *from, *to_next;
1268 from = vlib_frame_vector_args (from_frame);
1269 n_left_from = from_frame->n_vectors;
1271 next_index = node->cached_next_index;
1273 int encap_pkts = 0, bsid_pkts = 0;
1275 while (n_left_from > 0)
1279 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1282 while (n_left_from >= 8 && n_left_to_next >= 4)
1284 u32 bi0, bi1, bi2, bi3;
1285 vlib_buffer_t *b0, *b1, *b2, *b3;
1286 u32 next0, next1, next2, next3;
1287 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1288 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1289 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1290 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1292 /* Prefetch next iteration. */
1294 vlib_buffer_t *p4, *p5, *p6, *p7;
1296 p4 = vlib_get_buffer (vm, from[4]);
1297 p5 = vlib_get_buffer (vm, from[5]);
1298 p6 = vlib_get_buffer (vm, from[6]);
1299 p7 = vlib_get_buffer (vm, from[7]);
1301 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1302 vlib_prefetch_buffer_header (p4, LOAD);
1303 vlib_prefetch_buffer_header (p5, LOAD);
1304 vlib_prefetch_buffer_header (p6, LOAD);
1305 vlib_prefetch_buffer_header (p7, LOAD);
1307 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1308 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1309 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1310 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1313 to_next[0] = bi0 = from[0];
1314 to_next[1] = bi1 = from[1];
1315 to_next[2] = bi2 = from[2];
1316 to_next[3] = bi3 = from[3];
1320 n_left_to_next -= 4;
1322 b0 = vlib_get_buffer (vm, bi0);
1323 b1 = vlib_get_buffer (vm, bi1);
1324 b2 = vlib_get_buffer (vm, bi2);
1325 b3 = vlib_get_buffer (vm, bi3);
1328 pool_elt_at_index (sm->sid_lists,
1329 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1331 pool_elt_at_index (sm->sid_lists,
1332 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1334 pool_elt_at_index (sm->sid_lists,
1335 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1337 pool_elt_at_index (sm->sid_lists,
1338 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1340 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1341 vec_len (sl0->rewrite));
1342 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1343 vec_len (sl1->rewrite));
1344 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1345 vec_len (sl2->rewrite));
1346 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1347 vec_len (sl3->rewrite));
1349 ip0_encap = vlib_buffer_get_current (b0);
1350 ip1_encap = vlib_buffer_get_current (b1);
1351 ip2_encap = vlib_buffer_get_current (b2);
1352 ip3_encap = vlib_buffer_get_current (b3);
1354 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1355 sl0->rewrite, vec_len (sl0->rewrite));
1356 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1357 sl1->rewrite, vec_len (sl1->rewrite));
1358 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1359 sl2->rewrite, vec_len (sl2->rewrite));
1360 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1361 sl3->rewrite, vec_len (sl3->rewrite));
1363 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1364 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1365 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1366 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1368 ip0 = vlib_buffer_get_current (b0);
1369 ip1 = vlib_buffer_get_current (b1);
1370 ip2 = vlib_buffer_get_current (b2);
1371 ip3 = vlib_buffer_get_current (b3);
1373 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1374 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1375 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1376 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1378 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1380 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1382 sr_policy_rewrite_trace_t *tr =
1383 vlib_add_trace (vm, node, b0, sizeof (*tr));
1384 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1385 sizeof (tr->src.as_u8));
1386 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1387 sizeof (tr->dst.as_u8));
1390 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1392 sr_policy_rewrite_trace_t *tr =
1393 vlib_add_trace (vm, node, b1, sizeof (*tr));
1394 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1395 sizeof (tr->src.as_u8));
1396 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1397 sizeof (tr->dst.as_u8));
1400 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1402 sr_policy_rewrite_trace_t *tr =
1403 vlib_add_trace (vm, node, b2, sizeof (*tr));
1404 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1405 sizeof (tr->src.as_u8));
1406 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1407 sizeof (tr->dst.as_u8));
1410 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1412 sr_policy_rewrite_trace_t *tr =
1413 vlib_add_trace (vm, node, b3, sizeof (*tr));
1414 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1415 sizeof (tr->src.as_u8));
1416 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1417 sizeof (tr->dst.as_u8));
1422 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1423 n_left_to_next, bi0, bi1, bi2, bi3,
1424 next0, next1, next2, next3);
1427 /* Single loop for potentially the last three packets */
1428 while (n_left_from > 0 && n_left_to_next > 0)
1432 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1434 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1441 n_left_to_next -= 1;
1442 b0 = vlib_get_buffer (vm, bi0);
1445 pool_elt_at_index (sm->sid_lists,
1446 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1447 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1448 vec_len (sl0->rewrite));
1450 ip0_encap = vlib_buffer_get_current (b0);
1452 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1453 sl0->rewrite, vec_len (sl0->rewrite));
1454 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1456 ip0 = vlib_buffer_get_current (b0);
1458 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1460 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1461 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1463 sr_policy_rewrite_trace_t *tr =
1464 vlib_add_trace (vm, node, b0, sizeof (*tr));
1465 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1466 sizeof (tr->src.as_u8));
1467 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1468 sizeof (tr->dst.as_u8));
1472 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1473 n_left_to_next, bi0, next0);
1476 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1479 /* Update counters */
1480 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1481 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1483 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1484 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1487 return from_frame->n_vectors;
1491 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1492 .function = sr_policy_rewrite_encaps,
1493 .name = "sr-pl-rewrite-encaps",
1494 .vector_size = sizeof (u32),
1495 .format_trace = format_sr_policy_rewrite_trace,
1496 .type = VLIB_NODE_TYPE_INTERNAL,
1497 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1498 .error_strings = sr_policy_rewrite_error_strings,
1499 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1501 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1502 foreach_sr_policy_rewrite_next
1509 * @brief IPv4 encapsulation processing as per RFC2473
1511 static_always_inline void
1512 encaps_processing_v4 (vlib_node_runtime_t * node,
1514 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1517 ip6_sr_header_t *sr0;
1522 /* Inner IPv4: Decrement TTL & update checksum */
1523 ip0_encap->ttl -= 1;
1524 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1525 checksum0 += checksum0 >= 0xffff;
1526 ip0_encap->checksum = checksum0;
1528 /* Outer IPv6: Update length, FL, proto */
1529 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1530 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1531 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1532 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1533 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1534 (flow_label & 0x0000ffff));
1535 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1537 sr0 = (void *) (ip0 + 1);
1538 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1541 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1545 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1548 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1549 vlib_frame_t * from_frame)
1551 ip6_sr_main_t *sm = &sr_main;
1552 u32 n_left_from, next_index, *from, *to_next;
1554 from = vlib_frame_vector_args (from_frame);
1555 n_left_from = from_frame->n_vectors;
1557 next_index = node->cached_next_index;
1559 int encap_pkts = 0, bsid_pkts = 0;
1561 while (n_left_from > 0)
1565 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1568 while (n_left_from >= 8 && n_left_to_next >= 4)
1570 u32 bi0, bi1, bi2, bi3;
1571 vlib_buffer_t *b0, *b1, *b2, *b3;
1572 u32 next0, next1, next2, next3;
1573 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1574 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1575 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1576 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1578 /* Prefetch next iteration. */
1580 vlib_buffer_t *p4, *p5, *p6, *p7;
1582 p4 = vlib_get_buffer (vm, from[4]);
1583 p5 = vlib_get_buffer (vm, from[5]);
1584 p6 = vlib_get_buffer (vm, from[6]);
1585 p7 = vlib_get_buffer (vm, from[7]);
1587 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1588 vlib_prefetch_buffer_header (p4, LOAD);
1589 vlib_prefetch_buffer_header (p5, LOAD);
1590 vlib_prefetch_buffer_header (p6, LOAD);
1591 vlib_prefetch_buffer_header (p7, LOAD);
1593 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1594 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1595 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1596 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1599 to_next[0] = bi0 = from[0];
1600 to_next[1] = bi1 = from[1];
1601 to_next[2] = bi2 = from[2];
1602 to_next[3] = bi3 = from[3];
1606 n_left_to_next -= 4;
1608 b0 = vlib_get_buffer (vm, bi0);
1609 b1 = vlib_get_buffer (vm, bi1);
1610 b2 = vlib_get_buffer (vm, bi2);
1611 b3 = vlib_get_buffer (vm, bi3);
1614 pool_elt_at_index (sm->sid_lists,
1615 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1617 pool_elt_at_index (sm->sid_lists,
1618 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1620 pool_elt_at_index (sm->sid_lists,
1621 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1623 pool_elt_at_index (sm->sid_lists,
1624 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1625 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1626 vec_len (sl0->rewrite));
1627 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1628 vec_len (sl1->rewrite));
1629 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1630 vec_len (sl2->rewrite));
1631 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1632 vec_len (sl3->rewrite));
1634 ip0_encap = vlib_buffer_get_current (b0);
1635 ip1_encap = vlib_buffer_get_current (b1);
1636 ip2_encap = vlib_buffer_get_current (b2);
1637 ip3_encap = vlib_buffer_get_current (b3);
1639 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1640 sl0->rewrite, vec_len (sl0->rewrite));
1641 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1642 sl1->rewrite, vec_len (sl1->rewrite));
1643 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1644 sl2->rewrite, vec_len (sl2->rewrite));
1645 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1646 sl3->rewrite, vec_len (sl3->rewrite));
1648 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1649 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1650 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1651 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1653 ip0 = vlib_buffer_get_current (b0);
1654 ip1 = vlib_buffer_get_current (b1);
1655 ip2 = vlib_buffer_get_current (b2);
1656 ip3 = vlib_buffer_get_current (b3);
1658 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1659 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1660 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1661 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1663 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1665 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1667 sr_policy_rewrite_trace_t *tr =
1668 vlib_add_trace (vm, node, b0, sizeof (*tr));
1669 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1670 sizeof (tr->src.as_u8));
1671 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1672 sizeof (tr->dst.as_u8));
1675 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1677 sr_policy_rewrite_trace_t *tr =
1678 vlib_add_trace (vm, node, b1, sizeof (*tr));
1679 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1680 sizeof (tr->src.as_u8));
1681 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1682 sizeof (tr->dst.as_u8));
1685 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1687 sr_policy_rewrite_trace_t *tr =
1688 vlib_add_trace (vm, node, b2, sizeof (*tr));
1689 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1690 sizeof (tr->src.as_u8));
1691 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1692 sizeof (tr->dst.as_u8));
1695 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1697 sr_policy_rewrite_trace_t *tr =
1698 vlib_add_trace (vm, node, b3, sizeof (*tr));
1699 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1700 sizeof (tr->src.as_u8));
1701 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1702 sizeof (tr->dst.as_u8));
1707 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1708 n_left_to_next, bi0, bi1, bi2, bi3,
1709 next0, next1, next2, next3);
1712 /* Single loop for potentially the last three packets */
1713 while (n_left_from > 0 && n_left_to_next > 0)
1717 ip6_header_t *ip0 = 0;
1718 ip4_header_t *ip0_encap = 0;
1720 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1727 n_left_to_next -= 1;
1728 b0 = vlib_get_buffer (vm, bi0);
1731 pool_elt_at_index (sm->sid_lists,
1732 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1733 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1734 vec_len (sl0->rewrite));
1736 ip0_encap = vlib_buffer_get_current (b0);
1738 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1739 sl0->rewrite, vec_len (sl0->rewrite));
1740 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1742 ip0 = vlib_buffer_get_current (b0);
1744 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1746 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1747 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1749 sr_policy_rewrite_trace_t *tr =
1750 vlib_add_trace (vm, node, b0, sizeof (*tr));
1751 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1752 sizeof (tr->src.as_u8));
1753 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1754 sizeof (tr->dst.as_u8));
1758 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1759 n_left_to_next, bi0, next0);
1762 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1765 /* Update counters */
1766 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1767 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1769 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1770 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1773 return from_frame->n_vectors;
1777 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1778 .function = sr_policy_rewrite_encaps_v4,
1779 .name = "sr-pl-rewrite-encaps-v4",
1780 .vector_size = sizeof (u32),
1781 .format_trace = format_sr_policy_rewrite_trace,
1782 .type = VLIB_NODE_TYPE_INTERNAL,
1783 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1784 .error_strings = sr_policy_rewrite_error_strings,
1785 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1787 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1788 foreach_sr_policy_rewrite_next
1795 ip_flow_hash (void *data)
1797 ip4_header_t *iph = (ip4_header_t *) data;
1799 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1800 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1802 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1808 return (*((u64 *) m) & 0xffffffffffff);
1812 l2_flow_hash (vlib_buffer_t * b0)
1814 ethernet_header_t *eh;
1816 uword is_ip, eh_size;
1819 eh = vlib_buffer_get_current (b0);
1820 eh_type = clib_net_to_host_u16 (eh->type);
1821 eh_size = ethernet_buffer_header_size (b0);
1823 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1825 /* since we have 2 cache lines, use them */
1827 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1831 b = mac_to_u64 ((u8 *) eh->dst_address);
1832 c = mac_to_u64 ((u8 *) eh->src_address);
1833 hash_mix64 (a, b, c);
1839 * @brief Graph node for applying a SR policy into a L2 frame
1842 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1843 vlib_frame_t * from_frame)
1845 ip6_sr_main_t *sm = &sr_main;
1846 u32 n_left_from, next_index, *from, *to_next;
1848 from = vlib_frame_vector_args (from_frame);
1849 n_left_from = from_frame->n_vectors;
1851 next_index = node->cached_next_index;
1853 int encap_pkts = 0, bsid_pkts = 0;
1855 while (n_left_from > 0)
1859 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1862 while (n_left_from >= 8 && n_left_to_next >= 4)
1864 u32 bi0, bi1, bi2, bi3;
1865 vlib_buffer_t *b0, *b1, *b2, *b3;
1866 u32 next0, next1, next2, next3;
1867 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1868 ethernet_header_t *en0, *en1, *en2, *en3;
1869 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1870 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1871 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1872 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1873 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1875 /* Prefetch next iteration. */
1877 vlib_buffer_t *p4, *p5, *p6, *p7;
1879 p4 = vlib_get_buffer (vm, from[4]);
1880 p5 = vlib_get_buffer (vm, from[5]);
1881 p6 = vlib_get_buffer (vm, from[6]);
1882 p7 = vlib_get_buffer (vm, from[7]);
1884 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1885 vlib_prefetch_buffer_header (p4, LOAD);
1886 vlib_prefetch_buffer_header (p5, LOAD);
1887 vlib_prefetch_buffer_header (p6, LOAD);
1888 vlib_prefetch_buffer_header (p7, LOAD);
1890 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1891 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1892 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1893 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1896 to_next[0] = bi0 = from[0];
1897 to_next[1] = bi1 = from[1];
1898 to_next[2] = bi2 = from[2];
1899 to_next[3] = bi3 = from[3];
1903 n_left_to_next -= 4;
1905 b0 = vlib_get_buffer (vm, bi0);
1906 b1 = vlib_get_buffer (vm, bi1);
1907 b2 = vlib_get_buffer (vm, bi2);
1908 b3 = vlib_get_buffer (vm, bi3);
1910 sp0 = pool_elt_at_index (sm->sr_policies,
1911 sm->sw_iface_sr_policies[vnet_buffer
1915 sp1 = pool_elt_at_index (sm->sr_policies,
1916 sm->sw_iface_sr_policies[vnet_buffer
1920 sp2 = pool_elt_at_index (sm->sr_policies,
1921 sm->sw_iface_sr_policies[vnet_buffer
1925 sp3 = pool_elt_at_index (sm->sr_policies,
1926 sm->sw_iface_sr_policies[vnet_buffer
1929 flow_label0 = l2_flow_hash (b0);
1930 flow_label1 = l2_flow_hash (b1);
1931 flow_label2 = l2_flow_hash (b2);
1932 flow_label3 = l2_flow_hash (b3);
1934 if (vec_len (sp0->segments_lists) == 1)
1935 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1938 vnet_buffer (b0)->ip.flow_hash = flow_label0;
1939 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1940 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1941 (vec_len (sp0->segments_lists) - 1))];
1944 if (vec_len (sp1->segments_lists) == 1)
1945 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1948 vnet_buffer (b1)->ip.flow_hash = flow_label1;
1949 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1950 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1951 (vec_len (sp1->segments_lists) - 1))];
1954 if (vec_len (sp2->segments_lists) == 1)
1955 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1958 vnet_buffer (b2)->ip.flow_hash = flow_label2;
1959 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1960 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1961 (vec_len (sp2->segments_lists) - 1))];
1964 if (vec_len (sp3->segments_lists) == 1)
1965 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1968 vnet_buffer (b3)->ip.flow_hash = flow_label3;
1969 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1970 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1971 (vec_len (sp3->segments_lists) - 1))];
1975 pool_elt_at_index (sm->sid_lists,
1976 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1978 pool_elt_at_index (sm->sid_lists,
1979 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1981 pool_elt_at_index (sm->sid_lists,
1982 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1984 pool_elt_at_index (sm->sid_lists,
1985 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1987 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1988 vec_len (sl0->rewrite));
1989 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1990 vec_len (sl1->rewrite));
1991 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1992 vec_len (sl2->rewrite));
1993 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1994 vec_len (sl3->rewrite));
1996 en0 = vlib_buffer_get_current (b0);
1997 en1 = vlib_buffer_get_current (b1);
1998 en2 = vlib_buffer_get_current (b2);
1999 en3 = vlib_buffer_get_current (b3);
2001 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2002 sl0->rewrite, vec_len (sl0->rewrite));
2003 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2004 sl1->rewrite, vec_len (sl1->rewrite));
2005 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2006 sl2->rewrite, vec_len (sl2->rewrite));
2007 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2008 sl3->rewrite, vec_len (sl3->rewrite));
2010 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2011 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2012 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2013 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2015 ip0 = vlib_buffer_get_current (b0);
2016 ip1 = vlib_buffer_get_current (b1);
2017 ip2 = vlib_buffer_get_current (b2);
2018 ip3 = vlib_buffer_get_current (b3);
2020 ip0->payload_length =
2021 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2022 ip1->payload_length =
2023 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2024 ip2->payload_length =
2025 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2026 ip3->payload_length =
2027 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2029 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2031 sr0 = (void *) (ip0 + 1);
2032 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2035 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2037 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2039 sr1 = (void *) (ip1 + 1);
2040 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2043 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2045 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2047 sr2 = (void *) (ip2 + 1);
2048 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2051 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2053 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2055 sr3 = (void *) (ip3 + 1);
2056 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2059 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2061 /* TC is set to 0 for all ethernet frames, should be taken from COS
2062 * od DSCP of encapsulated packet in the future */
2063 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2064 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2065 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2066 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2067 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2068 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2069 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2070 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2072 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2074 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2076 sr_policy_rewrite_trace_t *tr =
2077 vlib_add_trace (vm, node, b0, sizeof (*tr));
2078 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2079 sizeof (tr->src.as_u8));
2080 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2081 sizeof (tr->dst.as_u8));
2084 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2086 sr_policy_rewrite_trace_t *tr =
2087 vlib_add_trace (vm, node, b1, sizeof (*tr));
2088 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2089 sizeof (tr->src.as_u8));
2090 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2091 sizeof (tr->dst.as_u8));
2094 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2096 sr_policy_rewrite_trace_t *tr =
2097 vlib_add_trace (vm, node, b2, sizeof (*tr));
2098 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2099 sizeof (tr->src.as_u8));
2100 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2101 sizeof (tr->dst.as_u8));
2104 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2106 sr_policy_rewrite_trace_t *tr =
2107 vlib_add_trace (vm, node, b3, sizeof (*tr));
2108 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2109 sizeof (tr->src.as_u8));
2110 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2111 sizeof (tr->dst.as_u8));
2116 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2117 n_left_to_next, bi0, bi1, bi2, bi3,
2118 next0, next1, next2, next3);
2121 /* Single loop for potentially the last three packets */
2122 while (n_left_from > 0 && n_left_to_next > 0)
2126 ip6_header_t *ip0 = 0;
2127 ip6_sr_header_t *sr0;
2128 ethernet_header_t *en0;
2129 ip6_sr_policy_t *sp0;
2131 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2139 n_left_to_next -= 1;
2140 b0 = vlib_get_buffer (vm, bi0);
2142 /* Find the SR policy */
2143 sp0 = pool_elt_at_index (sm->sr_policies,
2144 sm->sw_iface_sr_policies[vnet_buffer
2147 flow_label0 = l2_flow_hash (b0);
2149 /* In case there is more than one SL, LB among them */
2150 if (vec_len (sp0->segments_lists) == 1)
2151 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2154 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2155 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2156 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2157 (vec_len (sp0->segments_lists) - 1))];
2160 pool_elt_at_index (sm->sid_lists,
2161 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2162 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2163 vec_len (sl0->rewrite));
2165 en0 = vlib_buffer_get_current (b0);
2167 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2168 sl0->rewrite, vec_len (sl0->rewrite));
2170 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2172 ip0 = vlib_buffer_get_current (b0);
2174 ip0->payload_length =
2175 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2177 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2179 sr0 = (void *) (ip0 + 1);
2180 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2183 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2185 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2186 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2188 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2189 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2191 sr_policy_rewrite_trace_t *tr =
2192 vlib_add_trace (vm, node, b0, sizeof (*tr));
2193 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2194 sizeof (tr->src.as_u8));
2195 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2196 sizeof (tr->dst.as_u8));
2200 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2201 n_left_to_next, bi0, next0);
2204 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2207 /* Update counters */
2208 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2209 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2211 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2212 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2215 return from_frame->n_vectors;
2219 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2220 .function = sr_policy_rewrite_encaps_l2,
2221 .name = "sr-pl-rewrite-encaps-l2",
2222 .vector_size = sizeof (u32),
2223 .format_trace = format_sr_policy_rewrite_trace,
2224 .type = VLIB_NODE_TYPE_INTERNAL,
2225 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2226 .error_strings = sr_policy_rewrite_error_strings,
2227 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2229 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2230 foreach_sr_policy_rewrite_next
2237 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2240 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2241 vlib_frame_t * from_frame)
2243 ip6_sr_main_t *sm = &sr_main;
2244 u32 n_left_from, next_index, *from, *to_next;
2246 from = vlib_frame_vector_args (from_frame);
2247 n_left_from = from_frame->n_vectors;
2249 next_index = node->cached_next_index;
2251 int insert_pkts = 0, bsid_pkts = 0;
2253 while (n_left_from > 0)
2257 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2260 while (n_left_from >= 8 && n_left_to_next >= 4)
2262 u32 bi0, bi1, bi2, bi3;
2263 vlib_buffer_t *b0, *b1, *b2, *b3;
2264 u32 next0, next1, next2, next3;
2265 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2266 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2267 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2268 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2269 u16 new_l0, new_l1, new_l2, new_l3;
2271 /* Prefetch next iteration. */
2273 vlib_buffer_t *p4, *p5, *p6, *p7;
2275 p4 = vlib_get_buffer (vm, from[4]);
2276 p5 = vlib_get_buffer (vm, from[5]);
2277 p6 = vlib_get_buffer (vm, from[6]);
2278 p7 = vlib_get_buffer (vm, from[7]);
2280 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2281 vlib_prefetch_buffer_header (p4, LOAD);
2282 vlib_prefetch_buffer_header (p5, LOAD);
2283 vlib_prefetch_buffer_header (p6, LOAD);
2284 vlib_prefetch_buffer_header (p7, LOAD);
2286 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2287 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2288 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2289 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2292 to_next[0] = bi0 = from[0];
2293 to_next[1] = bi1 = from[1];
2294 to_next[2] = bi2 = from[2];
2295 to_next[3] = bi3 = from[3];
2299 n_left_to_next -= 4;
2301 b0 = vlib_get_buffer (vm, bi0);
2302 b1 = vlib_get_buffer (vm, bi1);
2303 b2 = vlib_get_buffer (vm, bi2);
2304 b3 = vlib_get_buffer (vm, bi3);
2307 pool_elt_at_index (sm->sid_lists,
2308 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2310 pool_elt_at_index (sm->sid_lists,
2311 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2313 pool_elt_at_index (sm->sid_lists,
2314 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2316 pool_elt_at_index (sm->sid_lists,
2317 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2318 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2319 vec_len (sl0->rewrite));
2320 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2321 vec_len (sl1->rewrite));
2322 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2323 vec_len (sl2->rewrite));
2324 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2325 vec_len (sl3->rewrite));
2327 ip0 = vlib_buffer_get_current (b0);
2328 ip1 = vlib_buffer_get_current (b1);
2329 ip2 = vlib_buffer_get_current (b2);
2330 ip3 = vlib_buffer_get_current (b3);
2332 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2334 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2335 ip6_ext_header_len (ip0 + 1));
2337 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2339 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2341 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2342 ip6_ext_header_len (ip1 + 1));
2344 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2346 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2348 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2349 ip6_ext_header_len (ip2 + 1));
2351 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2353 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2355 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2356 ip6_ext_header_len (ip3 + 1));
2358 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2360 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2361 (void *) sr0 - (void *) ip0);
2362 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2363 (void *) sr1 - (void *) ip1);
2364 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2365 (void *) sr2 - (void *) ip2);
2366 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2367 (void *) sr3 - (void *) ip3);
2369 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2370 sl0->rewrite, vec_len (sl0->rewrite));
2371 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2372 sl1->rewrite, vec_len (sl1->rewrite));
2373 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2374 sl2->rewrite, vec_len (sl2->rewrite));
2375 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2376 sl3->rewrite, vec_len (sl3->rewrite));
2378 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2379 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2380 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2381 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2383 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2384 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2385 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2386 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2388 ip0->hop_limit -= 1;
2389 ip1->hop_limit -= 1;
2390 ip2->hop_limit -= 1;
2391 ip3->hop_limit -= 1;
2394 clib_net_to_host_u16 (ip0->payload_length) +
2395 vec_len (sl0->rewrite);
2397 clib_net_to_host_u16 (ip1->payload_length) +
2398 vec_len (sl1->rewrite);
2400 clib_net_to_host_u16 (ip2->payload_length) +
2401 vec_len (sl2->rewrite);
2403 clib_net_to_host_u16 (ip3->payload_length) +
2404 vec_len (sl3->rewrite);
2406 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2407 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2408 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2409 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2411 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2412 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2413 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2414 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2416 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2417 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2418 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2419 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2420 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2421 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2422 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2423 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2425 ip0->dst_address.as_u64[0] =
2426 (sr0->segments + sr0->segments_left)->as_u64[0];
2427 ip0->dst_address.as_u64[1] =
2428 (sr0->segments + sr0->segments_left)->as_u64[1];
2429 ip1->dst_address.as_u64[0] =
2430 (sr1->segments + sr1->segments_left)->as_u64[0];
2431 ip1->dst_address.as_u64[1] =
2432 (sr1->segments + sr1->segments_left)->as_u64[1];
2433 ip2->dst_address.as_u64[0] =
2434 (sr2->segments + sr2->segments_left)->as_u64[0];
2435 ip2->dst_address.as_u64[1] =
2436 (sr2->segments + sr2->segments_left)->as_u64[1];
2437 ip3->dst_address.as_u64[0] =
2438 (sr3->segments + sr3->segments_left)->as_u64[0];
2439 ip3->dst_address.as_u64[1] =
2440 (sr3->segments + sr3->segments_left)->as_u64[1];
2442 ip6_ext_header_t *ip_ext;
2443 if (ip0 + 1 == (void *) sr0)
2445 sr0->protocol = ip0->protocol;
2446 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2450 ip_ext = (void *) (ip0 + 1);
2451 sr0->protocol = ip_ext->next_hdr;
2452 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2455 if (ip1 + 1 == (void *) sr1)
2457 sr1->protocol = ip1->protocol;
2458 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2462 ip_ext = (void *) (ip2 + 1);
2463 sr2->protocol = ip_ext->next_hdr;
2464 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2467 if (ip2 + 1 == (void *) sr2)
2469 sr2->protocol = ip2->protocol;
2470 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2474 ip_ext = (void *) (ip2 + 1);
2475 sr2->protocol = ip_ext->next_hdr;
2476 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2479 if (ip3 + 1 == (void *) sr3)
2481 sr3->protocol = ip3->protocol;
2482 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2486 ip_ext = (void *) (ip3 + 1);
2487 sr3->protocol = ip_ext->next_hdr;
2488 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2493 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2495 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2497 sr_policy_rewrite_trace_t *tr =
2498 vlib_add_trace (vm, node, b0, sizeof (*tr));
2499 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2500 sizeof (tr->src.as_u8));
2501 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2502 sizeof (tr->dst.as_u8));
2505 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2507 sr_policy_rewrite_trace_t *tr =
2508 vlib_add_trace (vm, node, b1, sizeof (*tr));
2509 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2510 sizeof (tr->src.as_u8));
2511 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2512 sizeof (tr->dst.as_u8));
2515 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2517 sr_policy_rewrite_trace_t *tr =
2518 vlib_add_trace (vm, node, b2, sizeof (*tr));
2519 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2520 sizeof (tr->src.as_u8));
2521 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2522 sizeof (tr->dst.as_u8));
2525 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2527 sr_policy_rewrite_trace_t *tr =
2528 vlib_add_trace (vm, node, b3, sizeof (*tr));
2529 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2530 sizeof (tr->src.as_u8));
2531 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2532 sizeof (tr->dst.as_u8));
2536 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2537 n_left_to_next, bi0, bi1, bi2, bi3,
2538 next0, next1, next2, next3);
2541 /* Single loop for potentially the last three packets */
2542 while (n_left_from > 0 && n_left_to_next > 0)
2546 ip6_header_t *ip0 = 0;
2547 ip6_sr_header_t *sr0 = 0;
2549 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2557 n_left_to_next -= 1;
2559 b0 = vlib_get_buffer (vm, bi0);
2561 pool_elt_at_index (sm->sid_lists,
2562 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2563 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2564 vec_len (sl0->rewrite));
2566 ip0 = vlib_buffer_get_current (b0);
2568 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2570 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2571 ip6_ext_header_len (ip0 + 1));
2573 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2575 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2576 (void *) sr0 - (void *) ip0);
2577 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2578 sl0->rewrite, vec_len (sl0->rewrite));
2580 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2582 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2583 ip0->hop_limit -= 1;
2585 clib_net_to_host_u16 (ip0->payload_length) +
2586 vec_len (sl0->rewrite);
2587 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2589 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2590 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2591 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2593 ip0->dst_address.as_u64[0] =
2594 (sr0->segments + sr0->segments_left)->as_u64[0];
2595 ip0->dst_address.as_u64[1] =
2596 (sr0->segments + sr0->segments_left)->as_u64[1];
2598 if (ip0 + 1 == (void *) sr0)
2600 sr0->protocol = ip0->protocol;
2601 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2605 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2606 sr0->protocol = ip_ext->next_hdr;
2607 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2610 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2611 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2613 sr_policy_rewrite_trace_t *tr =
2614 vlib_add_trace (vm, node, b0, sizeof (*tr));
2615 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2616 sizeof (tr->src.as_u8));
2617 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2618 sizeof (tr->dst.as_u8));
2623 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2624 n_left_to_next, bi0, next0);
2627 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2630 /* Update counters */
2631 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2632 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2634 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2635 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2637 return from_frame->n_vectors;
2641 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2642 .function = sr_policy_rewrite_insert,
2643 .name = "sr-pl-rewrite-insert",
2644 .vector_size = sizeof (u32),
2645 .format_trace = format_sr_policy_rewrite_trace,
2646 .type = VLIB_NODE_TYPE_INTERNAL,
2647 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2648 .error_strings = sr_policy_rewrite_error_strings,
2649 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2651 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2652 foreach_sr_policy_rewrite_next
2659 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2662 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2663 vlib_frame_t * from_frame)
2665 ip6_sr_main_t *sm = &sr_main;
2666 u32 n_left_from, next_index, *from, *to_next;
2668 from = vlib_frame_vector_args (from_frame);
2669 n_left_from = from_frame->n_vectors;
2671 next_index = node->cached_next_index;
2673 int insert_pkts = 0, bsid_pkts = 0;
2675 while (n_left_from > 0)
2679 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2682 while (n_left_from >= 8 && n_left_to_next >= 4)
2684 u32 bi0, bi1, bi2, bi3;
2685 vlib_buffer_t *b0, *b1, *b2, *b3;
2686 u32 next0, next1, next2, next3;
2687 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2688 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2689 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2690 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2691 u16 new_l0, new_l1, new_l2, new_l3;
2693 /* Prefetch next iteration. */
2695 vlib_buffer_t *p4, *p5, *p6, *p7;
2697 p4 = vlib_get_buffer (vm, from[4]);
2698 p5 = vlib_get_buffer (vm, from[5]);
2699 p6 = vlib_get_buffer (vm, from[6]);
2700 p7 = vlib_get_buffer (vm, from[7]);
2702 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2703 vlib_prefetch_buffer_header (p4, LOAD);
2704 vlib_prefetch_buffer_header (p5, LOAD);
2705 vlib_prefetch_buffer_header (p6, LOAD);
2706 vlib_prefetch_buffer_header (p7, LOAD);
2708 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2709 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2710 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2711 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2714 to_next[0] = bi0 = from[0];
2715 to_next[1] = bi1 = from[1];
2716 to_next[2] = bi2 = from[2];
2717 to_next[3] = bi3 = from[3];
2721 n_left_to_next -= 4;
2723 b0 = vlib_get_buffer (vm, bi0);
2724 b1 = vlib_get_buffer (vm, bi1);
2725 b2 = vlib_get_buffer (vm, bi2);
2726 b3 = vlib_get_buffer (vm, bi3);
2729 pool_elt_at_index (sm->sid_lists,
2730 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2732 pool_elt_at_index (sm->sid_lists,
2733 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2735 pool_elt_at_index (sm->sid_lists,
2736 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2738 pool_elt_at_index (sm->sid_lists,
2739 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2740 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2741 vec_len (sl0->rewrite_bsid));
2742 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2743 vec_len (sl1->rewrite_bsid));
2744 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2745 vec_len (sl2->rewrite_bsid));
2746 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2747 vec_len (sl3->rewrite_bsid));
2749 ip0 = vlib_buffer_get_current (b0);
2750 ip1 = vlib_buffer_get_current (b1);
2751 ip2 = vlib_buffer_get_current (b2);
2752 ip3 = vlib_buffer_get_current (b3);
2754 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2756 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2757 ip6_ext_header_len (ip0 + 1));
2759 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2761 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2763 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2764 ip6_ext_header_len (ip1 + 1));
2766 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2768 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2770 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2771 ip6_ext_header_len (ip2 + 1));
2773 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2775 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2777 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2778 ip6_ext_header_len (ip3 + 1));
2780 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2782 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2783 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2784 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2785 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2786 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2787 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2788 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2789 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2791 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2792 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2793 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2794 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2795 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2796 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2797 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2798 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2800 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2801 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2802 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2803 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2805 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2806 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2807 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2808 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2810 ip0->hop_limit -= 1;
2811 ip1->hop_limit -= 1;
2812 ip2->hop_limit -= 1;
2813 ip3->hop_limit -= 1;
2816 clib_net_to_host_u16 (ip0->payload_length) +
2817 vec_len (sl0->rewrite_bsid);
2819 clib_net_to_host_u16 (ip1->payload_length) +
2820 vec_len (sl1->rewrite_bsid);
2822 clib_net_to_host_u16 (ip2->payload_length) +
2823 vec_len (sl2->rewrite_bsid);
2825 clib_net_to_host_u16 (ip3->payload_length) +
2826 vec_len (sl3->rewrite_bsid);
2828 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2829 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2830 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2831 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2833 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2834 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2835 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2836 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2838 ip0->dst_address.as_u64[0] =
2839 (sr0->segments + sr0->segments_left)->as_u64[0];
2840 ip0->dst_address.as_u64[1] =
2841 (sr0->segments + sr0->segments_left)->as_u64[1];
2842 ip1->dst_address.as_u64[0] =
2843 (sr1->segments + sr1->segments_left)->as_u64[0];
2844 ip1->dst_address.as_u64[1] =
2845 (sr1->segments + sr1->segments_left)->as_u64[1];
2846 ip2->dst_address.as_u64[0] =
2847 (sr2->segments + sr2->segments_left)->as_u64[0];
2848 ip2->dst_address.as_u64[1] =
2849 (sr2->segments + sr2->segments_left)->as_u64[1];
2850 ip3->dst_address.as_u64[0] =
2851 (sr3->segments + sr3->segments_left)->as_u64[0];
2852 ip3->dst_address.as_u64[1] =
2853 (sr3->segments + sr3->segments_left)->as_u64[1];
2855 ip6_ext_header_t *ip_ext;
2856 if (ip0 + 1 == (void *) sr0)
2858 sr0->protocol = ip0->protocol;
2859 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2863 ip_ext = (void *) (ip0 + 1);
2864 sr0->protocol = ip_ext->next_hdr;
2865 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2868 if (ip1 + 1 == (void *) sr1)
2870 sr1->protocol = ip1->protocol;
2871 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2875 ip_ext = (void *) (ip2 + 1);
2876 sr2->protocol = ip_ext->next_hdr;
2877 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2880 if (ip2 + 1 == (void *) sr2)
2882 sr2->protocol = ip2->protocol;
2883 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2887 ip_ext = (void *) (ip2 + 1);
2888 sr2->protocol = ip_ext->next_hdr;
2889 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2892 if (ip3 + 1 == (void *) sr3)
2894 sr3->protocol = ip3->protocol;
2895 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2899 ip_ext = (void *) (ip3 + 1);
2900 sr3->protocol = ip_ext->next_hdr;
2901 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2906 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2908 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2910 sr_policy_rewrite_trace_t *tr =
2911 vlib_add_trace (vm, node, b0, sizeof (*tr));
2912 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2913 sizeof (tr->src.as_u8));
2914 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2915 sizeof (tr->dst.as_u8));
2918 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2920 sr_policy_rewrite_trace_t *tr =
2921 vlib_add_trace (vm, node, b1, sizeof (*tr));
2922 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2923 sizeof (tr->src.as_u8));
2924 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2925 sizeof (tr->dst.as_u8));
2928 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2930 sr_policy_rewrite_trace_t *tr =
2931 vlib_add_trace (vm, node, b2, sizeof (*tr));
2932 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2933 sizeof (tr->src.as_u8));
2934 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2935 sizeof (tr->dst.as_u8));
2938 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2940 sr_policy_rewrite_trace_t *tr =
2941 vlib_add_trace (vm, node, b3, sizeof (*tr));
2942 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2943 sizeof (tr->src.as_u8));
2944 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2945 sizeof (tr->dst.as_u8));
2949 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2950 n_left_to_next, bi0, bi1, bi2, bi3,
2951 next0, next1, next2, next3);
2954 /* Single loop for potentially the last three packets */
2955 while (n_left_from > 0 && n_left_to_next > 0)
2959 ip6_header_t *ip0 = 0;
2960 ip6_sr_header_t *sr0 = 0;
2962 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2970 n_left_to_next -= 1;
2972 b0 = vlib_get_buffer (vm, bi0);
2974 pool_elt_at_index (sm->sid_lists,
2975 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2976 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2977 vec_len (sl0->rewrite_bsid));
2979 ip0 = vlib_buffer_get_current (b0);
2981 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2983 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2984 ip6_ext_header_len (ip0 + 1));
2986 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2988 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2989 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2990 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2991 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2993 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2995 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2996 ip0->hop_limit -= 1;
2998 clib_net_to_host_u16 (ip0->payload_length) +
2999 vec_len (sl0->rewrite_bsid);
3000 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3002 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3004 ip0->dst_address.as_u64[0] =
3005 (sr0->segments + sr0->segments_left)->as_u64[0];
3006 ip0->dst_address.as_u64[1] =
3007 (sr0->segments + sr0->segments_left)->as_u64[1];
3009 if (ip0 + 1 == (void *) sr0)
3011 sr0->protocol = ip0->protocol;
3012 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3016 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3017 sr0->protocol = ip_ext->next_hdr;
3018 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3021 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3022 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3024 sr_policy_rewrite_trace_t *tr =
3025 vlib_add_trace (vm, node, b0, sizeof (*tr));
3026 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3027 sizeof (tr->src.as_u8));
3028 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3029 sizeof (tr->dst.as_u8));
3034 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3035 n_left_to_next, bi0, next0);
3038 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3041 /* Update counters */
3042 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3043 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3045 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3046 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3048 return from_frame->n_vectors;
3052 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3053 .function = sr_policy_rewrite_b_insert,
3054 .name = "sr-pl-rewrite-b-insert",
3055 .vector_size = sizeof (u32),
3056 .format_trace = format_sr_policy_rewrite_trace,
3057 .type = VLIB_NODE_TYPE_INTERNAL,
3058 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3059 .error_strings = sr_policy_rewrite_error_strings,
3060 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3062 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3063 foreach_sr_policy_rewrite_next
3070 * @brief Function BSID encapsulation
3072 static_always_inline void
3073 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3076 ip6_sr_header_t * sr0, u32 * next0)
3078 ip6_address_t *new_dst0;
3080 if (PREDICT_FALSE (!sr0))
3081 goto error_bsid_encaps;
3083 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3085 if (PREDICT_TRUE (sr0->segments_left != 0))
3087 sr0->segments_left -= 1;
3088 new_dst0 = (ip6_address_t *) (sr0->segments);
3089 new_dst0 += sr0->segments_left;
3090 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3091 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3097 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3098 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3102 * @brief Graph node for applying a SR policy BSID - Encapsulation
3105 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3106 vlib_frame_t * from_frame)
3108 ip6_sr_main_t *sm = &sr_main;
3109 u32 n_left_from, next_index, *from, *to_next;
3111 from = vlib_frame_vector_args (from_frame);
3112 n_left_from = from_frame->n_vectors;
3114 next_index = node->cached_next_index;
3116 int encap_pkts = 0, bsid_pkts = 0;
3118 while (n_left_from > 0)
3122 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3125 while (n_left_from >= 8 && n_left_to_next >= 4)
3127 u32 bi0, bi1, bi2, bi3;
3128 vlib_buffer_t *b0, *b1, *b2, *b3;
3129 u32 next0, next1, next2, next3;
3130 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3131 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3132 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3133 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3134 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3136 /* Prefetch next iteration. */
3138 vlib_buffer_t *p4, *p5, *p6, *p7;
3140 p4 = vlib_get_buffer (vm, from[4]);
3141 p5 = vlib_get_buffer (vm, from[5]);
3142 p6 = vlib_get_buffer (vm, from[6]);
3143 p7 = vlib_get_buffer (vm, from[7]);
3145 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3146 vlib_prefetch_buffer_header (p4, LOAD);
3147 vlib_prefetch_buffer_header (p5, LOAD);
3148 vlib_prefetch_buffer_header (p6, LOAD);
3149 vlib_prefetch_buffer_header (p7, LOAD);
3151 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3152 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3153 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3154 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3157 to_next[0] = bi0 = from[0];
3158 to_next[1] = bi1 = from[1];
3159 to_next[2] = bi2 = from[2];
3160 to_next[3] = bi3 = from[3];
3164 n_left_to_next -= 4;
3166 b0 = vlib_get_buffer (vm, bi0);
3167 b1 = vlib_get_buffer (vm, bi1);
3168 b2 = vlib_get_buffer (vm, bi2);
3169 b3 = vlib_get_buffer (vm, bi3);
3172 pool_elt_at_index (sm->sid_lists,
3173 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3175 pool_elt_at_index (sm->sid_lists,
3176 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3178 pool_elt_at_index (sm->sid_lists,
3179 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3181 pool_elt_at_index (sm->sid_lists,
3182 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3183 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3184 vec_len (sl0->rewrite));
3185 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3186 vec_len (sl1->rewrite));
3187 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3188 vec_len (sl2->rewrite));
3189 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3190 vec_len (sl3->rewrite));
3192 ip0_encap = vlib_buffer_get_current (b0);
3193 ip1_encap = vlib_buffer_get_current (b1);
3194 ip2_encap = vlib_buffer_get_current (b2);
3195 ip3_encap = vlib_buffer_get_current (b3);
3198 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3201 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3204 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3207 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3210 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3211 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3212 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3213 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3215 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3216 sl0->rewrite, vec_len (sl0->rewrite));
3217 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3218 sl1->rewrite, vec_len (sl1->rewrite));
3219 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3220 sl2->rewrite, vec_len (sl2->rewrite));
3221 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3222 sl3->rewrite, vec_len (sl3->rewrite));
3224 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3225 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3226 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3227 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3229 ip0 = vlib_buffer_get_current (b0);
3230 ip1 = vlib_buffer_get_current (b1);
3231 ip2 = vlib_buffer_get_current (b2);
3232 ip3 = vlib_buffer_get_current (b3);
3234 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3235 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3236 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3237 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3239 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3241 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3243 sr_policy_rewrite_trace_t *tr =
3244 vlib_add_trace (vm, node, b0, sizeof (*tr));
3245 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3246 sizeof (tr->src.as_u8));
3247 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3248 sizeof (tr->dst.as_u8));
3251 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3253 sr_policy_rewrite_trace_t *tr =
3254 vlib_add_trace (vm, node, b1, sizeof (*tr));
3255 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3256 sizeof (tr->src.as_u8));
3257 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3258 sizeof (tr->dst.as_u8));
3261 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3263 sr_policy_rewrite_trace_t *tr =
3264 vlib_add_trace (vm, node, b2, sizeof (*tr));
3265 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3266 sizeof (tr->src.as_u8));
3267 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3268 sizeof (tr->dst.as_u8));
3271 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3273 sr_policy_rewrite_trace_t *tr =
3274 vlib_add_trace (vm, node, b3, sizeof (*tr));
3275 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3276 sizeof (tr->src.as_u8));
3277 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3278 sizeof (tr->dst.as_u8));
3283 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3284 n_left_to_next, bi0, bi1, bi2, bi3,
3285 next0, next1, next2, next3);
3288 /* Single loop for potentially the last three packets */
3289 while (n_left_from > 0 && n_left_to_next > 0)
3293 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3294 ip6_sr_header_t *sr0;
3296 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3303 n_left_to_next -= 1;
3304 b0 = vlib_get_buffer (vm, bi0);
3307 pool_elt_at_index (sm->sid_lists,
3308 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3309 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3310 vec_len (sl0->rewrite));
3312 ip0_encap = vlib_buffer_get_current (b0);
3314 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3316 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3318 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3319 sl0->rewrite, vec_len (sl0->rewrite));
3320 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3322 ip0 = vlib_buffer_get_current (b0);
3324 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3326 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3327 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3329 sr_policy_rewrite_trace_t *tr =
3330 vlib_add_trace (vm, node, b0, sizeof (*tr));
3331 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3332 sizeof (tr->src.as_u8));
3333 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3334 sizeof (tr->dst.as_u8));
3338 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3339 n_left_to_next, bi0, next0);
3342 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3345 /* Update counters */
3346 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3347 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3349 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3350 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3353 return from_frame->n_vectors;
3357 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3358 .function = sr_policy_rewrite_b_encaps,
3359 .name = "sr-pl-rewrite-b-encaps",
3360 .vector_size = sizeof (u32),
3361 .format_trace = format_sr_policy_rewrite_trace,
3362 .type = VLIB_NODE_TYPE_INTERNAL,
3363 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3364 .error_strings = sr_policy_rewrite_error_strings,
3365 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3367 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3368 foreach_sr_policy_rewrite_next
3374 /*************************** SR Policy plugins ******************************/
3376 * @brief SR Policy plugin registry
3379 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3380 u8 * keyword_str, u8 * def_str,
3381 u8 * params_str, u8 prefix_length,
3383 format_function_t * ls_format,
3384 unformat_function_t * ls_unformat,
3385 sr_p_plugin_callback_t * creation_fn,
3386 sr_p_plugin_callback_t * removal_fn)
3388 ip6_sr_main_t *sm = &sr_main;
3391 sr_policy_fn_registration_t *plugin;
3393 /* Did this function exist? If so update it */
3394 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3397 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3399 /* Else create a new one and set hash key */
3402 pool_get (sm->policy_plugin_functions, plugin);
3403 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3404 plugin - sm->policy_plugin_functions);
3407 clib_memset (plugin, 0, sizeof (*plugin));
3409 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3410 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3411 plugin->prefix_length = prefix_length;
3412 plugin->ls_format = ls_format;
3413 plugin->ls_unformat = ls_unformat;
3414 plugin->creation = creation_fn;
3415 plugin->removal = removal_fn;
3416 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3417 plugin->function_name = format (0, "%s%c", fn_name, 0);
3418 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3419 plugin->def_str = format (0, "%s%c", def_str, 0);
3420 plugin->params_str = format (0, "%s%c", params_str, 0);
3422 return plugin->sr_policy_function_number;
3426 * @brief CLI function to 'show' all available SR LocalSID behaviors
3428 static clib_error_t *
3429 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3430 unformat_input_t * input,
3431 vlib_cli_command_t * cmd)
3433 ip6_sr_main_t *sm = &sr_main;
3434 sr_policy_fn_registration_t *plugin;
3435 sr_policy_fn_registration_t **plugins_vec = 0;
3438 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3441 pool_foreach (plugin, sm->policy_plugin_functions)
3442 { vec_add1 (plugins_vec, plugin); }
3445 vlib_cli_output (vm, "Plugin behaviors:\n");
3446 for (i = 0; i < vec_len (plugins_vec); i++)
3448 plugin = plugins_vec[i];
3449 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3451 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3457 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3458 .path = "show sr policy behaviors",
3459 .short_help = "show sr policy behaviors",
3460 .function = show_sr_policy_behaviors_command_fn,
3464 /*************************** SR Segment Lists DPOs ****************************/
3466 format_sr_segment_list_dpo (u8 * s, va_list * args)
3468 ip6_sr_main_t *sm = &sr_main;
3469 ip6_address_t *addr;
3472 index_t index = va_arg (*args, index_t);
3473 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3474 s = format (s, "SR: Segment List index:[%d]", index);
3475 s = format (s, "\n\tSegments:");
3477 sl = pool_elt_at_index (sm->sid_lists, index);
3479 s = format (s, "< ");
3480 vec_foreach (addr, sl->segments)
3482 s = format (s, "%U, ", format_ip6_address, addr);
3484 s = format (s, "\b\b > - ");
3485 s = format (s, "Weight: %u", sl->weight);
3490 const static dpo_vft_t sr_policy_rewrite_vft = {
3491 .dv_lock = sr_dpo_lock,
3492 .dv_unlock = sr_dpo_unlock,
3493 .dv_format = format_sr_segment_list_dpo,
3496 const static char *const sr_pr_encaps_ip6_nodes[] = {
3497 "sr-pl-rewrite-encaps",
3501 const static char *const sr_pr_encaps_ip4_nodes[] = {
3502 "sr-pl-rewrite-encaps-v4",
3506 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3507 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3508 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3511 const static char *const sr_pr_insert_ip6_nodes[] = {
3512 "sr-pl-rewrite-insert",
3516 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3517 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3520 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3521 "sr-pl-rewrite-b-insert",
3525 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3526 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3529 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3530 "sr-pl-rewrite-b-encaps",
3534 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3535 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3538 /********************* SR Policy Rewrite initialization ***********************/
3540 * @brief SR Policy Rewrite initialization
3543 sr_policy_rewrite_init (vlib_main_t * vm)
3545 ip6_sr_main_t *sm = &sr_main;
3547 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3548 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3549 sizeof (ip6_address_t));
3551 /* Init SR VPO DPOs type */
3552 sr_pr_encaps_dpo_type =
3553 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3555 sr_pr_insert_dpo_type =
3556 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3558 sr_pr_bsid_encaps_dpo_type =
3559 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3561 sr_pr_bsid_insert_dpo_type =
3562 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3564 /* Register the L2 encaps node used in HW redirect */
3565 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3567 sm->fib_table_ip6 = (u32) ~ 0;
3568 sm->fib_table_ip4 = (u32) ~ 0;
3573 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3577 * fd.io coding-style-patch-verification: ON
3580 * eval: (c-set-style "gnu")