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)
1242 ip0_encap->hop_limit -= 1;
1244 ip0->payload_length + sizeof (ip6_header_t) +
1245 clib_net_to_host_u16 (ip0_encap->payload_length);
1246 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1247 ip0->ip_version_traffic_class_and_flow_label =
1248 ip0_encap->ip_version_traffic_class_and_flow_label;
1252 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1255 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1256 vlib_frame_t * from_frame)
1258 ip6_sr_main_t *sm = &sr_main;
1259 u32 n_left_from, next_index, *from, *to_next;
1261 from = vlib_frame_vector_args (from_frame);
1262 n_left_from = from_frame->n_vectors;
1264 next_index = node->cached_next_index;
1266 int encap_pkts = 0, bsid_pkts = 0;
1268 while (n_left_from > 0)
1272 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1275 while (n_left_from >= 8 && n_left_to_next >= 4)
1277 u32 bi0, bi1, bi2, bi3;
1278 vlib_buffer_t *b0, *b1, *b2, *b3;
1279 u32 next0, next1, next2, next3;
1280 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1281 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1282 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1283 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1285 /* Prefetch next iteration. */
1287 vlib_buffer_t *p4, *p5, *p6, *p7;
1289 p4 = vlib_get_buffer (vm, from[4]);
1290 p5 = vlib_get_buffer (vm, from[5]);
1291 p6 = vlib_get_buffer (vm, from[6]);
1292 p7 = vlib_get_buffer (vm, from[7]);
1294 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1295 vlib_prefetch_buffer_header (p4, LOAD);
1296 vlib_prefetch_buffer_header (p5, LOAD);
1297 vlib_prefetch_buffer_header (p6, LOAD);
1298 vlib_prefetch_buffer_header (p7, LOAD);
1300 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1301 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1302 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1303 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1306 to_next[0] = bi0 = from[0];
1307 to_next[1] = bi1 = from[1];
1308 to_next[2] = bi2 = from[2];
1309 to_next[3] = bi3 = from[3];
1313 n_left_to_next -= 4;
1315 b0 = vlib_get_buffer (vm, bi0);
1316 b1 = vlib_get_buffer (vm, bi1);
1317 b2 = vlib_get_buffer (vm, bi2);
1318 b3 = vlib_get_buffer (vm, bi3);
1321 pool_elt_at_index (sm->sid_lists,
1322 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1324 pool_elt_at_index (sm->sid_lists,
1325 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1327 pool_elt_at_index (sm->sid_lists,
1328 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1330 pool_elt_at_index (sm->sid_lists,
1331 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1333 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1334 vec_len (sl0->rewrite));
1335 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1336 vec_len (sl1->rewrite));
1337 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1338 vec_len (sl2->rewrite));
1339 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1340 vec_len (sl3->rewrite));
1342 ip0_encap = vlib_buffer_get_current (b0);
1343 ip1_encap = vlib_buffer_get_current (b1);
1344 ip2_encap = vlib_buffer_get_current (b2);
1345 ip3_encap = vlib_buffer_get_current (b3);
1347 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1348 sl0->rewrite, vec_len (sl0->rewrite));
1349 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1350 sl1->rewrite, vec_len (sl1->rewrite));
1351 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1352 sl2->rewrite, vec_len (sl2->rewrite));
1353 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1354 sl3->rewrite, vec_len (sl3->rewrite));
1356 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1357 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1358 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1359 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1361 ip0 = vlib_buffer_get_current (b0);
1362 ip1 = vlib_buffer_get_current (b1);
1363 ip2 = vlib_buffer_get_current (b2);
1364 ip3 = vlib_buffer_get_current (b3);
1366 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1367 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1368 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1369 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1371 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1373 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1375 sr_policy_rewrite_trace_t *tr =
1376 vlib_add_trace (vm, node, b0, sizeof (*tr));
1377 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1378 sizeof (tr->src.as_u8));
1379 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1380 sizeof (tr->dst.as_u8));
1383 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1385 sr_policy_rewrite_trace_t *tr =
1386 vlib_add_trace (vm, node, b1, sizeof (*tr));
1387 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1388 sizeof (tr->src.as_u8));
1389 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1390 sizeof (tr->dst.as_u8));
1393 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1395 sr_policy_rewrite_trace_t *tr =
1396 vlib_add_trace (vm, node, b2, sizeof (*tr));
1397 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1398 sizeof (tr->src.as_u8));
1399 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1400 sizeof (tr->dst.as_u8));
1403 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1405 sr_policy_rewrite_trace_t *tr =
1406 vlib_add_trace (vm, node, b3, sizeof (*tr));
1407 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1408 sizeof (tr->src.as_u8));
1409 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1410 sizeof (tr->dst.as_u8));
1415 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1416 n_left_to_next, bi0, bi1, bi2, bi3,
1417 next0, next1, next2, next3);
1420 /* Single loop for potentially the last three packets */
1421 while (n_left_from > 0 && n_left_to_next > 0)
1425 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1427 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1434 n_left_to_next -= 1;
1435 b0 = vlib_get_buffer (vm, bi0);
1438 pool_elt_at_index (sm->sid_lists,
1439 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1440 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1441 vec_len (sl0->rewrite));
1443 ip0_encap = vlib_buffer_get_current (b0);
1445 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1446 sl0->rewrite, vec_len (sl0->rewrite));
1447 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1449 ip0 = vlib_buffer_get_current (b0);
1451 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1453 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1454 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1456 sr_policy_rewrite_trace_t *tr =
1457 vlib_add_trace (vm, node, b0, sizeof (*tr));
1458 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1459 sizeof (tr->src.as_u8));
1460 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1461 sizeof (tr->dst.as_u8));
1465 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1466 n_left_to_next, bi0, next0);
1469 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1472 /* Update counters */
1473 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1474 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1476 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1477 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1480 return from_frame->n_vectors;
1484 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1485 .function = sr_policy_rewrite_encaps,
1486 .name = "sr-pl-rewrite-encaps",
1487 .vector_size = sizeof (u32),
1488 .format_trace = format_sr_policy_rewrite_trace,
1489 .type = VLIB_NODE_TYPE_INTERNAL,
1490 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1491 .error_strings = sr_policy_rewrite_error_strings,
1492 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1494 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1495 foreach_sr_policy_rewrite_next
1502 * @brief IPv4 encapsulation processing as per RFC2473
1504 static_always_inline void
1505 encaps_processing_v4 (vlib_node_runtime_t * node,
1507 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1510 ip6_sr_header_t *sr0;
1514 /* Inner IPv4: Decrement TTL & update checksum */
1515 ip0_encap->ttl -= 1;
1516 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1517 checksum0 += checksum0 >= 0xffff;
1518 ip0_encap->checksum = checksum0;
1520 /* Outer IPv6: Update length, FL, proto */
1521 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1522 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1523 ip0->ip_version_traffic_class_and_flow_label =
1524 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1525 ((ip0_encap->tos & 0xFF) << 20));
1526 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1528 sr0 = (void *) (ip0 + 1);
1529 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1532 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1536 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1539 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1540 vlib_frame_t * from_frame)
1542 ip6_sr_main_t *sm = &sr_main;
1543 u32 n_left_from, next_index, *from, *to_next;
1545 from = vlib_frame_vector_args (from_frame);
1546 n_left_from = from_frame->n_vectors;
1548 next_index = node->cached_next_index;
1550 int encap_pkts = 0, bsid_pkts = 0;
1552 while (n_left_from > 0)
1556 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1559 while (n_left_from >= 8 && n_left_to_next >= 4)
1561 u32 bi0, bi1, bi2, bi3;
1562 vlib_buffer_t *b0, *b1, *b2, *b3;
1563 u32 next0, next1, next2, next3;
1564 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1565 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1566 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1567 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1569 /* Prefetch next iteration. */
1571 vlib_buffer_t *p4, *p5, *p6, *p7;
1573 p4 = vlib_get_buffer (vm, from[4]);
1574 p5 = vlib_get_buffer (vm, from[5]);
1575 p6 = vlib_get_buffer (vm, from[6]);
1576 p7 = vlib_get_buffer (vm, from[7]);
1578 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1579 vlib_prefetch_buffer_header (p4, LOAD);
1580 vlib_prefetch_buffer_header (p5, LOAD);
1581 vlib_prefetch_buffer_header (p6, LOAD);
1582 vlib_prefetch_buffer_header (p7, LOAD);
1584 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1585 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1586 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1587 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1590 to_next[0] = bi0 = from[0];
1591 to_next[1] = bi1 = from[1];
1592 to_next[2] = bi2 = from[2];
1593 to_next[3] = bi3 = from[3];
1597 n_left_to_next -= 4;
1599 b0 = vlib_get_buffer (vm, bi0);
1600 b1 = vlib_get_buffer (vm, bi1);
1601 b2 = vlib_get_buffer (vm, bi2);
1602 b3 = vlib_get_buffer (vm, bi3);
1605 pool_elt_at_index (sm->sid_lists,
1606 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1608 pool_elt_at_index (sm->sid_lists,
1609 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1611 pool_elt_at_index (sm->sid_lists,
1612 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1614 pool_elt_at_index (sm->sid_lists,
1615 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1616 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1617 vec_len (sl0->rewrite));
1618 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1619 vec_len (sl1->rewrite));
1620 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1621 vec_len (sl2->rewrite));
1622 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1623 vec_len (sl3->rewrite));
1625 ip0_encap = vlib_buffer_get_current (b0);
1626 ip1_encap = vlib_buffer_get_current (b1);
1627 ip2_encap = vlib_buffer_get_current (b2);
1628 ip3_encap = vlib_buffer_get_current (b3);
1630 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1631 sl0->rewrite, vec_len (sl0->rewrite));
1632 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1633 sl1->rewrite, vec_len (sl1->rewrite));
1634 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1635 sl2->rewrite, vec_len (sl2->rewrite));
1636 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1637 sl3->rewrite, vec_len (sl3->rewrite));
1639 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1640 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1641 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1642 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1644 ip0 = vlib_buffer_get_current (b0);
1645 ip1 = vlib_buffer_get_current (b1);
1646 ip2 = vlib_buffer_get_current (b2);
1647 ip3 = vlib_buffer_get_current (b3);
1649 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1650 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1651 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1652 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1654 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1656 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1658 sr_policy_rewrite_trace_t *tr =
1659 vlib_add_trace (vm, node, b0, sizeof (*tr));
1660 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1661 sizeof (tr->src.as_u8));
1662 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1663 sizeof (tr->dst.as_u8));
1666 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1668 sr_policy_rewrite_trace_t *tr =
1669 vlib_add_trace (vm, node, b1, sizeof (*tr));
1670 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1671 sizeof (tr->src.as_u8));
1672 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1673 sizeof (tr->dst.as_u8));
1676 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1678 sr_policy_rewrite_trace_t *tr =
1679 vlib_add_trace (vm, node, b2, sizeof (*tr));
1680 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1681 sizeof (tr->src.as_u8));
1682 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1683 sizeof (tr->dst.as_u8));
1686 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1688 sr_policy_rewrite_trace_t *tr =
1689 vlib_add_trace (vm, node, b3, sizeof (*tr));
1690 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1691 sizeof (tr->src.as_u8));
1692 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1693 sizeof (tr->dst.as_u8));
1698 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1699 n_left_to_next, bi0, bi1, bi2, bi3,
1700 next0, next1, next2, next3);
1703 /* Single loop for potentially the last three packets */
1704 while (n_left_from > 0 && n_left_to_next > 0)
1708 ip6_header_t *ip0 = 0;
1709 ip4_header_t *ip0_encap = 0;
1711 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1718 n_left_to_next -= 1;
1719 b0 = vlib_get_buffer (vm, bi0);
1722 pool_elt_at_index (sm->sid_lists,
1723 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1724 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1725 vec_len (sl0->rewrite));
1727 ip0_encap = vlib_buffer_get_current (b0);
1729 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1730 sl0->rewrite, vec_len (sl0->rewrite));
1731 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1733 ip0 = vlib_buffer_get_current (b0);
1735 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1737 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1738 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1740 sr_policy_rewrite_trace_t *tr =
1741 vlib_add_trace (vm, node, b0, sizeof (*tr));
1742 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1743 sizeof (tr->src.as_u8));
1744 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1745 sizeof (tr->dst.as_u8));
1749 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1750 n_left_to_next, bi0, next0);
1753 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1756 /* Update counters */
1757 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1758 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1760 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1761 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1764 return from_frame->n_vectors;
1768 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1769 .function = sr_policy_rewrite_encaps_v4,
1770 .name = "sr-pl-rewrite-encaps-v4",
1771 .vector_size = sizeof (u32),
1772 .format_trace = format_sr_policy_rewrite_trace,
1773 .type = VLIB_NODE_TYPE_INTERNAL,
1774 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1775 .error_strings = sr_policy_rewrite_error_strings,
1776 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1778 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1779 foreach_sr_policy_rewrite_next
1786 ip_flow_hash (void *data)
1788 ip4_header_t *iph = (ip4_header_t *) data;
1790 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1791 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1793 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1799 return (*((u64 *) m) & 0xffffffffffff);
1803 l2_flow_hash (vlib_buffer_t * b0)
1805 ethernet_header_t *eh;
1807 uword is_ip, eh_size;
1810 eh = vlib_buffer_get_current (b0);
1811 eh_type = clib_net_to_host_u16 (eh->type);
1812 eh_size = ethernet_buffer_header_size (b0);
1814 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1816 /* since we have 2 cache lines, use them */
1818 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1822 b = mac_to_u64 ((u8 *) eh->dst_address);
1823 c = mac_to_u64 ((u8 *) eh->src_address);
1824 hash_mix64 (a, b, c);
1830 * @brief Graph node for applying a SR policy into a L2 frame
1833 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1834 vlib_frame_t * from_frame)
1836 ip6_sr_main_t *sm = &sr_main;
1837 u32 n_left_from, next_index, *from, *to_next;
1839 from = vlib_frame_vector_args (from_frame);
1840 n_left_from = from_frame->n_vectors;
1842 next_index = node->cached_next_index;
1844 int encap_pkts = 0, bsid_pkts = 0;
1846 while (n_left_from > 0)
1850 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1853 while (n_left_from >= 8 && n_left_to_next >= 4)
1855 u32 bi0, bi1, bi2, bi3;
1856 vlib_buffer_t *b0, *b1, *b2, *b3;
1857 u32 next0, next1, next2, next3;
1858 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1859 ethernet_header_t *en0, *en1, *en2, *en3;
1860 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1861 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1862 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1863 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1865 /* Prefetch next iteration. */
1867 vlib_buffer_t *p4, *p5, *p6, *p7;
1869 p4 = vlib_get_buffer (vm, from[4]);
1870 p5 = vlib_get_buffer (vm, from[5]);
1871 p6 = vlib_get_buffer (vm, from[6]);
1872 p7 = vlib_get_buffer (vm, from[7]);
1874 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1875 vlib_prefetch_buffer_header (p4, LOAD);
1876 vlib_prefetch_buffer_header (p5, LOAD);
1877 vlib_prefetch_buffer_header (p6, LOAD);
1878 vlib_prefetch_buffer_header (p7, LOAD);
1880 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1881 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1882 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1883 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1886 to_next[0] = bi0 = from[0];
1887 to_next[1] = bi1 = from[1];
1888 to_next[2] = bi2 = from[2];
1889 to_next[3] = bi3 = from[3];
1893 n_left_to_next -= 4;
1895 b0 = vlib_get_buffer (vm, bi0);
1896 b1 = vlib_get_buffer (vm, bi1);
1897 b2 = vlib_get_buffer (vm, bi2);
1898 b3 = vlib_get_buffer (vm, bi3);
1900 sp0 = pool_elt_at_index (sm->sr_policies,
1901 sm->sw_iface_sr_policies[vnet_buffer
1905 sp1 = pool_elt_at_index (sm->sr_policies,
1906 sm->sw_iface_sr_policies[vnet_buffer
1910 sp2 = pool_elt_at_index (sm->sr_policies,
1911 sm->sw_iface_sr_policies[vnet_buffer
1915 sp3 = pool_elt_at_index (sm->sr_policies,
1916 sm->sw_iface_sr_policies[vnet_buffer
1920 if (vec_len (sp0->segments_lists) == 1)
1921 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1924 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1925 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1926 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1927 (vec_len (sp0->segments_lists) - 1))];
1930 if (vec_len (sp1->segments_lists) == 1)
1931 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1934 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1935 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1936 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1937 (vec_len (sp1->segments_lists) - 1))];
1940 if (vec_len (sp2->segments_lists) == 1)
1941 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1944 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1945 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1946 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1947 (vec_len (sp2->segments_lists) - 1))];
1950 if (vec_len (sp3->segments_lists) == 1)
1951 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1954 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1955 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1956 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1957 (vec_len (sp3->segments_lists) - 1))];
1961 pool_elt_at_index (sm->sid_lists,
1962 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1964 pool_elt_at_index (sm->sid_lists,
1965 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1967 pool_elt_at_index (sm->sid_lists,
1968 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1970 pool_elt_at_index (sm->sid_lists,
1971 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1973 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1974 vec_len (sl0->rewrite));
1975 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1976 vec_len (sl1->rewrite));
1977 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1978 vec_len (sl2->rewrite));
1979 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1980 vec_len (sl3->rewrite));
1982 en0 = vlib_buffer_get_current (b0);
1983 en1 = vlib_buffer_get_current (b1);
1984 en2 = vlib_buffer_get_current (b2);
1985 en3 = vlib_buffer_get_current (b3);
1987 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1988 sl0->rewrite, vec_len (sl0->rewrite));
1989 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1990 sl1->rewrite, vec_len (sl1->rewrite));
1991 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1992 sl2->rewrite, vec_len (sl2->rewrite));
1993 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1994 sl3->rewrite, vec_len (sl3->rewrite));
1996 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1997 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1998 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1999 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2001 ip0 = vlib_buffer_get_current (b0);
2002 ip1 = vlib_buffer_get_current (b1);
2003 ip2 = vlib_buffer_get_current (b2);
2004 ip3 = vlib_buffer_get_current (b3);
2006 ip0->payload_length =
2007 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2008 ip1->payload_length =
2009 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2010 ip2->payload_length =
2011 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2012 ip3->payload_length =
2013 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2015 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2017 sr0 = (void *) (ip0 + 1);
2018 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2021 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2023 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2025 sr1 = (void *) (ip1 + 1);
2026 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2029 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2031 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2033 sr2 = (void *) (ip2 + 1);
2034 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2037 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2039 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2041 sr3 = (void *) (ip3 + 1);
2042 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2045 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2047 /* Which Traffic class and flow label do I set ? */
2048 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2050 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2052 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2054 sr_policy_rewrite_trace_t *tr =
2055 vlib_add_trace (vm, node, b0, sizeof (*tr));
2056 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2057 sizeof (tr->src.as_u8));
2058 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2059 sizeof (tr->dst.as_u8));
2062 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2064 sr_policy_rewrite_trace_t *tr =
2065 vlib_add_trace (vm, node, b1, sizeof (*tr));
2066 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2067 sizeof (tr->src.as_u8));
2068 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2069 sizeof (tr->dst.as_u8));
2072 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2074 sr_policy_rewrite_trace_t *tr =
2075 vlib_add_trace (vm, node, b2, sizeof (*tr));
2076 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2077 sizeof (tr->src.as_u8));
2078 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2079 sizeof (tr->dst.as_u8));
2082 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2084 sr_policy_rewrite_trace_t *tr =
2085 vlib_add_trace (vm, node, b3, sizeof (*tr));
2086 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2087 sizeof (tr->src.as_u8));
2088 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2089 sizeof (tr->dst.as_u8));
2094 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2095 n_left_to_next, bi0, bi1, bi2, bi3,
2096 next0, next1, next2, next3);
2099 /* Single loop for potentially the last three packets */
2100 while (n_left_from > 0 && n_left_to_next > 0)
2104 ip6_header_t *ip0 = 0;
2105 ip6_sr_header_t *sr0;
2106 ethernet_header_t *en0;
2107 ip6_sr_policy_t *sp0;
2109 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2116 n_left_to_next -= 1;
2117 b0 = vlib_get_buffer (vm, bi0);
2119 /* Find the SR policy */
2120 sp0 = pool_elt_at_index (sm->sr_policies,
2121 sm->sw_iface_sr_policies[vnet_buffer
2125 /* In case there is more than one SL, LB among them */
2126 if (vec_len (sp0->segments_lists) == 1)
2127 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2130 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2131 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2132 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2133 (vec_len (sp0->segments_lists) - 1))];
2136 pool_elt_at_index (sm->sid_lists,
2137 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2138 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2139 vec_len (sl0->rewrite));
2141 en0 = vlib_buffer_get_current (b0);
2143 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2144 sl0->rewrite, vec_len (sl0->rewrite));
2146 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2148 ip0 = vlib_buffer_get_current (b0);
2150 ip0->payload_length =
2151 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2153 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2155 sr0 = (void *) (ip0 + 1);
2156 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2159 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2161 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2162 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2164 sr_policy_rewrite_trace_t *tr =
2165 vlib_add_trace (vm, node, b0, sizeof (*tr));
2166 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2167 sizeof (tr->src.as_u8));
2168 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2169 sizeof (tr->dst.as_u8));
2173 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2174 n_left_to_next, bi0, next0);
2177 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2180 /* Update counters */
2181 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2182 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2184 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2185 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2188 return from_frame->n_vectors;
2192 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2193 .function = sr_policy_rewrite_encaps_l2,
2194 .name = "sr-pl-rewrite-encaps-l2",
2195 .vector_size = sizeof (u32),
2196 .format_trace = format_sr_policy_rewrite_trace,
2197 .type = VLIB_NODE_TYPE_INTERNAL,
2198 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2199 .error_strings = sr_policy_rewrite_error_strings,
2200 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2202 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2203 foreach_sr_policy_rewrite_next
2210 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2213 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2214 vlib_frame_t * from_frame)
2216 ip6_sr_main_t *sm = &sr_main;
2217 u32 n_left_from, next_index, *from, *to_next;
2219 from = vlib_frame_vector_args (from_frame);
2220 n_left_from = from_frame->n_vectors;
2222 next_index = node->cached_next_index;
2224 int insert_pkts = 0, bsid_pkts = 0;
2226 while (n_left_from > 0)
2230 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2233 while (n_left_from >= 8 && n_left_to_next >= 4)
2235 u32 bi0, bi1, bi2, bi3;
2236 vlib_buffer_t *b0, *b1, *b2, *b3;
2237 u32 next0, next1, next2, next3;
2238 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2239 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2240 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2241 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2242 u16 new_l0, new_l1, new_l2, new_l3;
2244 /* Prefetch next iteration. */
2246 vlib_buffer_t *p4, *p5, *p6, *p7;
2248 p4 = vlib_get_buffer (vm, from[4]);
2249 p5 = vlib_get_buffer (vm, from[5]);
2250 p6 = vlib_get_buffer (vm, from[6]);
2251 p7 = vlib_get_buffer (vm, from[7]);
2253 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2254 vlib_prefetch_buffer_header (p4, LOAD);
2255 vlib_prefetch_buffer_header (p5, LOAD);
2256 vlib_prefetch_buffer_header (p6, LOAD);
2257 vlib_prefetch_buffer_header (p7, LOAD);
2259 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2260 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2261 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2262 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2265 to_next[0] = bi0 = from[0];
2266 to_next[1] = bi1 = from[1];
2267 to_next[2] = bi2 = from[2];
2268 to_next[3] = bi3 = from[3];
2272 n_left_to_next -= 4;
2274 b0 = vlib_get_buffer (vm, bi0);
2275 b1 = vlib_get_buffer (vm, bi1);
2276 b2 = vlib_get_buffer (vm, bi2);
2277 b3 = vlib_get_buffer (vm, bi3);
2280 pool_elt_at_index (sm->sid_lists,
2281 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2283 pool_elt_at_index (sm->sid_lists,
2284 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2286 pool_elt_at_index (sm->sid_lists,
2287 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2289 pool_elt_at_index (sm->sid_lists,
2290 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2291 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2292 vec_len (sl0->rewrite));
2293 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2294 vec_len (sl1->rewrite));
2295 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2296 vec_len (sl2->rewrite));
2297 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2298 vec_len (sl3->rewrite));
2300 ip0 = vlib_buffer_get_current (b0);
2301 ip1 = vlib_buffer_get_current (b1);
2302 ip2 = vlib_buffer_get_current (b2);
2303 ip3 = vlib_buffer_get_current (b3);
2305 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2307 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2308 ip6_ext_header_len (ip0 + 1));
2310 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2312 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2314 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2315 ip6_ext_header_len (ip1 + 1));
2317 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2319 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2321 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2322 ip6_ext_header_len (ip2 + 1));
2324 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2326 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2328 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2329 ip6_ext_header_len (ip3 + 1));
2331 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2333 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2334 (void *) sr0 - (void *) ip0);
2335 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2336 (void *) sr1 - (void *) ip1);
2337 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2338 (void *) sr2 - (void *) ip2);
2339 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2340 (void *) sr3 - (void *) ip3);
2342 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2343 sl0->rewrite, vec_len (sl0->rewrite));
2344 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2345 sl1->rewrite, vec_len (sl1->rewrite));
2346 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2347 sl2->rewrite, vec_len (sl2->rewrite));
2348 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2349 sl3->rewrite, vec_len (sl3->rewrite));
2351 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2352 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2353 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2354 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2356 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2357 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2358 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2359 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2361 ip0->hop_limit -= 1;
2362 ip1->hop_limit -= 1;
2363 ip2->hop_limit -= 1;
2364 ip3->hop_limit -= 1;
2367 clib_net_to_host_u16 (ip0->payload_length) +
2368 vec_len (sl0->rewrite);
2370 clib_net_to_host_u16 (ip1->payload_length) +
2371 vec_len (sl1->rewrite);
2373 clib_net_to_host_u16 (ip2->payload_length) +
2374 vec_len (sl2->rewrite);
2376 clib_net_to_host_u16 (ip3->payload_length) +
2377 vec_len (sl3->rewrite);
2379 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2380 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2381 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2382 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2384 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2385 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2386 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2387 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2389 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2390 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2391 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2392 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2393 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2394 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2395 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2396 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2398 ip0->dst_address.as_u64[0] =
2399 (sr0->segments + sr0->segments_left)->as_u64[0];
2400 ip0->dst_address.as_u64[1] =
2401 (sr0->segments + sr0->segments_left)->as_u64[1];
2402 ip1->dst_address.as_u64[0] =
2403 (sr1->segments + sr1->segments_left)->as_u64[0];
2404 ip1->dst_address.as_u64[1] =
2405 (sr1->segments + sr1->segments_left)->as_u64[1];
2406 ip2->dst_address.as_u64[0] =
2407 (sr2->segments + sr2->segments_left)->as_u64[0];
2408 ip2->dst_address.as_u64[1] =
2409 (sr2->segments + sr2->segments_left)->as_u64[1];
2410 ip3->dst_address.as_u64[0] =
2411 (sr3->segments + sr3->segments_left)->as_u64[0];
2412 ip3->dst_address.as_u64[1] =
2413 (sr3->segments + sr3->segments_left)->as_u64[1];
2415 ip6_ext_header_t *ip_ext;
2416 if (ip0 + 1 == (void *) sr0)
2418 sr0->protocol = ip0->protocol;
2419 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2423 ip_ext = (void *) (ip0 + 1);
2424 sr0->protocol = ip_ext->next_hdr;
2425 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2428 if (ip1 + 1 == (void *) sr1)
2430 sr1->protocol = ip1->protocol;
2431 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2435 ip_ext = (void *) (ip2 + 1);
2436 sr2->protocol = ip_ext->next_hdr;
2437 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2440 if (ip2 + 1 == (void *) sr2)
2442 sr2->protocol = ip2->protocol;
2443 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2447 ip_ext = (void *) (ip2 + 1);
2448 sr2->protocol = ip_ext->next_hdr;
2449 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2452 if (ip3 + 1 == (void *) sr3)
2454 sr3->protocol = ip3->protocol;
2455 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2459 ip_ext = (void *) (ip3 + 1);
2460 sr3->protocol = ip_ext->next_hdr;
2461 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2466 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2468 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2470 sr_policy_rewrite_trace_t *tr =
2471 vlib_add_trace (vm, node, b0, sizeof (*tr));
2472 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2473 sizeof (tr->src.as_u8));
2474 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2475 sizeof (tr->dst.as_u8));
2478 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2480 sr_policy_rewrite_trace_t *tr =
2481 vlib_add_trace (vm, node, b1, sizeof (*tr));
2482 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2483 sizeof (tr->src.as_u8));
2484 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2485 sizeof (tr->dst.as_u8));
2488 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2490 sr_policy_rewrite_trace_t *tr =
2491 vlib_add_trace (vm, node, b2, sizeof (*tr));
2492 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2493 sizeof (tr->src.as_u8));
2494 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2495 sizeof (tr->dst.as_u8));
2498 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2500 sr_policy_rewrite_trace_t *tr =
2501 vlib_add_trace (vm, node, b3, sizeof (*tr));
2502 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2503 sizeof (tr->src.as_u8));
2504 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2505 sizeof (tr->dst.as_u8));
2509 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2510 n_left_to_next, bi0, bi1, bi2, bi3,
2511 next0, next1, next2, next3);
2514 /* Single loop for potentially the last three packets */
2515 while (n_left_from > 0 && n_left_to_next > 0)
2519 ip6_header_t *ip0 = 0;
2520 ip6_sr_header_t *sr0 = 0;
2522 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2530 n_left_to_next -= 1;
2532 b0 = vlib_get_buffer (vm, bi0);
2534 pool_elt_at_index (sm->sid_lists,
2535 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2536 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2537 vec_len (sl0->rewrite));
2539 ip0 = vlib_buffer_get_current (b0);
2541 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2543 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2544 ip6_ext_header_len (ip0 + 1));
2546 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2548 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2549 (void *) sr0 - (void *) ip0);
2550 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2551 sl0->rewrite, vec_len (sl0->rewrite));
2553 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2555 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2556 ip0->hop_limit -= 1;
2558 clib_net_to_host_u16 (ip0->payload_length) +
2559 vec_len (sl0->rewrite);
2560 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2562 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2563 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2564 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2566 ip0->dst_address.as_u64[0] =
2567 (sr0->segments + sr0->segments_left)->as_u64[0];
2568 ip0->dst_address.as_u64[1] =
2569 (sr0->segments + sr0->segments_left)->as_u64[1];
2571 if (ip0 + 1 == (void *) sr0)
2573 sr0->protocol = ip0->protocol;
2574 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2578 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2579 sr0->protocol = ip_ext->next_hdr;
2580 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2583 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2584 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2586 sr_policy_rewrite_trace_t *tr =
2587 vlib_add_trace (vm, node, b0, sizeof (*tr));
2588 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2589 sizeof (tr->src.as_u8));
2590 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2591 sizeof (tr->dst.as_u8));
2596 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2597 n_left_to_next, bi0, next0);
2600 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2603 /* Update counters */
2604 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2605 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2607 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2608 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2610 return from_frame->n_vectors;
2614 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2615 .function = sr_policy_rewrite_insert,
2616 .name = "sr-pl-rewrite-insert",
2617 .vector_size = sizeof (u32),
2618 .format_trace = format_sr_policy_rewrite_trace,
2619 .type = VLIB_NODE_TYPE_INTERNAL,
2620 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2621 .error_strings = sr_policy_rewrite_error_strings,
2622 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2624 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2625 foreach_sr_policy_rewrite_next
2632 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2635 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2636 vlib_frame_t * from_frame)
2638 ip6_sr_main_t *sm = &sr_main;
2639 u32 n_left_from, next_index, *from, *to_next;
2641 from = vlib_frame_vector_args (from_frame);
2642 n_left_from = from_frame->n_vectors;
2644 next_index = node->cached_next_index;
2646 int insert_pkts = 0, bsid_pkts = 0;
2648 while (n_left_from > 0)
2652 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2655 while (n_left_from >= 8 && n_left_to_next >= 4)
2657 u32 bi0, bi1, bi2, bi3;
2658 vlib_buffer_t *b0, *b1, *b2, *b3;
2659 u32 next0, next1, next2, next3;
2660 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2661 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2662 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2663 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2664 u16 new_l0, new_l1, new_l2, new_l3;
2666 /* Prefetch next iteration. */
2668 vlib_buffer_t *p4, *p5, *p6, *p7;
2670 p4 = vlib_get_buffer (vm, from[4]);
2671 p5 = vlib_get_buffer (vm, from[5]);
2672 p6 = vlib_get_buffer (vm, from[6]);
2673 p7 = vlib_get_buffer (vm, from[7]);
2675 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2676 vlib_prefetch_buffer_header (p4, LOAD);
2677 vlib_prefetch_buffer_header (p5, LOAD);
2678 vlib_prefetch_buffer_header (p6, LOAD);
2679 vlib_prefetch_buffer_header (p7, LOAD);
2681 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2682 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2683 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2684 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2687 to_next[0] = bi0 = from[0];
2688 to_next[1] = bi1 = from[1];
2689 to_next[2] = bi2 = from[2];
2690 to_next[3] = bi3 = from[3];
2694 n_left_to_next -= 4;
2696 b0 = vlib_get_buffer (vm, bi0);
2697 b1 = vlib_get_buffer (vm, bi1);
2698 b2 = vlib_get_buffer (vm, bi2);
2699 b3 = vlib_get_buffer (vm, bi3);
2702 pool_elt_at_index (sm->sid_lists,
2703 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2705 pool_elt_at_index (sm->sid_lists,
2706 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2708 pool_elt_at_index (sm->sid_lists,
2709 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2711 pool_elt_at_index (sm->sid_lists,
2712 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2713 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2714 vec_len (sl0->rewrite_bsid));
2715 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2716 vec_len (sl1->rewrite_bsid));
2717 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2718 vec_len (sl2->rewrite_bsid));
2719 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2720 vec_len (sl3->rewrite_bsid));
2722 ip0 = vlib_buffer_get_current (b0);
2723 ip1 = vlib_buffer_get_current (b1);
2724 ip2 = vlib_buffer_get_current (b2);
2725 ip3 = vlib_buffer_get_current (b3);
2727 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2729 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2730 ip6_ext_header_len (ip0 + 1));
2732 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2734 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2736 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2737 ip6_ext_header_len (ip1 + 1));
2739 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2741 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2743 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2744 ip6_ext_header_len (ip2 + 1));
2746 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2748 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2750 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2751 ip6_ext_header_len (ip3 + 1));
2753 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2755 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2756 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2757 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2758 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2759 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2760 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2761 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2762 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2764 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2765 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2766 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2767 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2768 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2769 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2770 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2771 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2773 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2774 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2775 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2776 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2778 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2779 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2780 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2781 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2783 ip0->hop_limit -= 1;
2784 ip1->hop_limit -= 1;
2785 ip2->hop_limit -= 1;
2786 ip3->hop_limit -= 1;
2789 clib_net_to_host_u16 (ip0->payload_length) +
2790 vec_len (sl0->rewrite_bsid);
2792 clib_net_to_host_u16 (ip1->payload_length) +
2793 vec_len (sl1->rewrite_bsid);
2795 clib_net_to_host_u16 (ip2->payload_length) +
2796 vec_len (sl2->rewrite_bsid);
2798 clib_net_to_host_u16 (ip3->payload_length) +
2799 vec_len (sl3->rewrite_bsid);
2801 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2802 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2803 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2804 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2806 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2807 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2808 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2809 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2811 ip0->dst_address.as_u64[0] =
2812 (sr0->segments + sr0->segments_left)->as_u64[0];
2813 ip0->dst_address.as_u64[1] =
2814 (sr0->segments + sr0->segments_left)->as_u64[1];
2815 ip1->dst_address.as_u64[0] =
2816 (sr1->segments + sr1->segments_left)->as_u64[0];
2817 ip1->dst_address.as_u64[1] =
2818 (sr1->segments + sr1->segments_left)->as_u64[1];
2819 ip2->dst_address.as_u64[0] =
2820 (sr2->segments + sr2->segments_left)->as_u64[0];
2821 ip2->dst_address.as_u64[1] =
2822 (sr2->segments + sr2->segments_left)->as_u64[1];
2823 ip3->dst_address.as_u64[0] =
2824 (sr3->segments + sr3->segments_left)->as_u64[0];
2825 ip3->dst_address.as_u64[1] =
2826 (sr3->segments + sr3->segments_left)->as_u64[1];
2828 ip6_ext_header_t *ip_ext;
2829 if (ip0 + 1 == (void *) sr0)
2831 sr0->protocol = ip0->protocol;
2832 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2836 ip_ext = (void *) (ip0 + 1);
2837 sr0->protocol = ip_ext->next_hdr;
2838 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2841 if (ip1 + 1 == (void *) sr1)
2843 sr1->protocol = ip1->protocol;
2844 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2848 ip_ext = (void *) (ip2 + 1);
2849 sr2->protocol = ip_ext->next_hdr;
2850 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2853 if (ip2 + 1 == (void *) sr2)
2855 sr2->protocol = ip2->protocol;
2856 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2860 ip_ext = (void *) (ip2 + 1);
2861 sr2->protocol = ip_ext->next_hdr;
2862 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2865 if (ip3 + 1 == (void *) sr3)
2867 sr3->protocol = ip3->protocol;
2868 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2872 ip_ext = (void *) (ip3 + 1);
2873 sr3->protocol = ip_ext->next_hdr;
2874 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2879 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2881 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2883 sr_policy_rewrite_trace_t *tr =
2884 vlib_add_trace (vm, node, b0, sizeof (*tr));
2885 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2886 sizeof (tr->src.as_u8));
2887 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2888 sizeof (tr->dst.as_u8));
2891 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2893 sr_policy_rewrite_trace_t *tr =
2894 vlib_add_trace (vm, node, b1, sizeof (*tr));
2895 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2896 sizeof (tr->src.as_u8));
2897 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2898 sizeof (tr->dst.as_u8));
2901 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2903 sr_policy_rewrite_trace_t *tr =
2904 vlib_add_trace (vm, node, b2, sizeof (*tr));
2905 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2906 sizeof (tr->src.as_u8));
2907 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2908 sizeof (tr->dst.as_u8));
2911 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2913 sr_policy_rewrite_trace_t *tr =
2914 vlib_add_trace (vm, node, b3, sizeof (*tr));
2915 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2916 sizeof (tr->src.as_u8));
2917 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2918 sizeof (tr->dst.as_u8));
2922 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2923 n_left_to_next, bi0, bi1, bi2, bi3,
2924 next0, next1, next2, next3);
2927 /* Single loop for potentially the last three packets */
2928 while (n_left_from > 0 && n_left_to_next > 0)
2932 ip6_header_t *ip0 = 0;
2933 ip6_sr_header_t *sr0 = 0;
2935 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2943 n_left_to_next -= 1;
2945 b0 = vlib_get_buffer (vm, bi0);
2947 pool_elt_at_index (sm->sid_lists,
2948 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2949 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2950 vec_len (sl0->rewrite_bsid));
2952 ip0 = vlib_buffer_get_current (b0);
2954 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2956 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2957 ip6_ext_header_len (ip0 + 1));
2959 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2961 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2962 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2963 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2964 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2966 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2968 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2969 ip0->hop_limit -= 1;
2971 clib_net_to_host_u16 (ip0->payload_length) +
2972 vec_len (sl0->rewrite_bsid);
2973 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2975 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2977 ip0->dst_address.as_u64[0] =
2978 (sr0->segments + sr0->segments_left)->as_u64[0];
2979 ip0->dst_address.as_u64[1] =
2980 (sr0->segments + sr0->segments_left)->as_u64[1];
2982 if (ip0 + 1 == (void *) sr0)
2984 sr0->protocol = ip0->protocol;
2985 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2989 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2990 sr0->protocol = ip_ext->next_hdr;
2991 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2994 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2995 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2997 sr_policy_rewrite_trace_t *tr =
2998 vlib_add_trace (vm, node, b0, sizeof (*tr));
2999 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3000 sizeof (tr->src.as_u8));
3001 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3002 sizeof (tr->dst.as_u8));
3007 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3008 n_left_to_next, bi0, next0);
3011 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3014 /* Update counters */
3015 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3016 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3018 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3019 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3021 return from_frame->n_vectors;
3025 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3026 .function = sr_policy_rewrite_b_insert,
3027 .name = "sr-pl-rewrite-b-insert",
3028 .vector_size = sizeof (u32),
3029 .format_trace = format_sr_policy_rewrite_trace,
3030 .type = VLIB_NODE_TYPE_INTERNAL,
3031 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3032 .error_strings = sr_policy_rewrite_error_strings,
3033 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3035 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3036 foreach_sr_policy_rewrite_next
3043 * @brief Function BSID encapsulation
3045 static_always_inline void
3046 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3049 ip6_sr_header_t * sr0, u32 * next0)
3051 ip6_address_t *new_dst0;
3053 if (PREDICT_FALSE (!sr0))
3054 goto error_bsid_encaps;
3056 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3058 if (PREDICT_TRUE (sr0->segments_left != 0))
3060 sr0->segments_left -= 1;
3061 new_dst0 = (ip6_address_t *) (sr0->segments);
3062 new_dst0 += sr0->segments_left;
3063 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3064 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3070 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3071 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3075 * @brief Graph node for applying a SR policy BSID - Encapsulation
3078 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3079 vlib_frame_t * from_frame)
3081 ip6_sr_main_t *sm = &sr_main;
3082 u32 n_left_from, next_index, *from, *to_next;
3084 from = vlib_frame_vector_args (from_frame);
3085 n_left_from = from_frame->n_vectors;
3087 next_index = node->cached_next_index;
3089 int encap_pkts = 0, bsid_pkts = 0;
3091 while (n_left_from > 0)
3095 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3098 while (n_left_from >= 8 && n_left_to_next >= 4)
3100 u32 bi0, bi1, bi2, bi3;
3101 vlib_buffer_t *b0, *b1, *b2, *b3;
3102 u32 next0, next1, next2, next3;
3103 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3104 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3105 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3106 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3107 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3109 /* Prefetch next iteration. */
3111 vlib_buffer_t *p4, *p5, *p6, *p7;
3113 p4 = vlib_get_buffer (vm, from[4]);
3114 p5 = vlib_get_buffer (vm, from[5]);
3115 p6 = vlib_get_buffer (vm, from[6]);
3116 p7 = vlib_get_buffer (vm, from[7]);
3118 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3119 vlib_prefetch_buffer_header (p4, LOAD);
3120 vlib_prefetch_buffer_header (p5, LOAD);
3121 vlib_prefetch_buffer_header (p6, LOAD);
3122 vlib_prefetch_buffer_header (p7, LOAD);
3124 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3125 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3126 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3127 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3130 to_next[0] = bi0 = from[0];
3131 to_next[1] = bi1 = from[1];
3132 to_next[2] = bi2 = from[2];
3133 to_next[3] = bi3 = from[3];
3137 n_left_to_next -= 4;
3139 b0 = vlib_get_buffer (vm, bi0);
3140 b1 = vlib_get_buffer (vm, bi1);
3141 b2 = vlib_get_buffer (vm, bi2);
3142 b3 = vlib_get_buffer (vm, bi3);
3145 pool_elt_at_index (sm->sid_lists,
3146 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3148 pool_elt_at_index (sm->sid_lists,
3149 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3151 pool_elt_at_index (sm->sid_lists,
3152 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3154 pool_elt_at_index (sm->sid_lists,
3155 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3156 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3157 vec_len (sl0->rewrite));
3158 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3159 vec_len (sl1->rewrite));
3160 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3161 vec_len (sl2->rewrite));
3162 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3163 vec_len (sl3->rewrite));
3165 ip0_encap = vlib_buffer_get_current (b0);
3166 ip1_encap = vlib_buffer_get_current (b1);
3167 ip2_encap = vlib_buffer_get_current (b2);
3168 ip3_encap = vlib_buffer_get_current (b3);
3171 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3174 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3177 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3180 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3183 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3184 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3185 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3186 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3188 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3189 sl0->rewrite, vec_len (sl0->rewrite));
3190 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3191 sl1->rewrite, vec_len (sl1->rewrite));
3192 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3193 sl2->rewrite, vec_len (sl2->rewrite));
3194 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3195 sl3->rewrite, vec_len (sl3->rewrite));
3197 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3198 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3199 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3200 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3202 ip0 = vlib_buffer_get_current (b0);
3203 ip1 = vlib_buffer_get_current (b1);
3204 ip2 = vlib_buffer_get_current (b2);
3205 ip3 = vlib_buffer_get_current (b3);
3207 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3208 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3209 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3210 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3212 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3214 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3216 sr_policy_rewrite_trace_t *tr =
3217 vlib_add_trace (vm, node, b0, sizeof (*tr));
3218 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3219 sizeof (tr->src.as_u8));
3220 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3221 sizeof (tr->dst.as_u8));
3224 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3226 sr_policy_rewrite_trace_t *tr =
3227 vlib_add_trace (vm, node, b1, sizeof (*tr));
3228 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3229 sizeof (tr->src.as_u8));
3230 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3231 sizeof (tr->dst.as_u8));
3234 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3236 sr_policy_rewrite_trace_t *tr =
3237 vlib_add_trace (vm, node, b2, sizeof (*tr));
3238 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3239 sizeof (tr->src.as_u8));
3240 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3241 sizeof (tr->dst.as_u8));
3244 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3246 sr_policy_rewrite_trace_t *tr =
3247 vlib_add_trace (vm, node, b3, sizeof (*tr));
3248 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3249 sizeof (tr->src.as_u8));
3250 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3251 sizeof (tr->dst.as_u8));
3256 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3257 n_left_to_next, bi0, bi1, bi2, bi3,
3258 next0, next1, next2, next3);
3261 /* Single loop for potentially the last three packets */
3262 while (n_left_from > 0 && n_left_to_next > 0)
3266 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3267 ip6_sr_header_t *sr0;
3269 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3276 n_left_to_next -= 1;
3277 b0 = vlib_get_buffer (vm, bi0);
3280 pool_elt_at_index (sm->sid_lists,
3281 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3282 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3283 vec_len (sl0->rewrite));
3285 ip0_encap = vlib_buffer_get_current (b0);
3287 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3289 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3291 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3292 sl0->rewrite, vec_len (sl0->rewrite));
3293 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3295 ip0 = vlib_buffer_get_current (b0);
3297 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3299 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3300 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3302 sr_policy_rewrite_trace_t *tr =
3303 vlib_add_trace (vm, node, b0, sizeof (*tr));
3304 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3305 sizeof (tr->src.as_u8));
3306 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3307 sizeof (tr->dst.as_u8));
3311 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3312 n_left_to_next, bi0, next0);
3315 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3318 /* Update counters */
3319 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3320 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3322 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3323 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3326 return from_frame->n_vectors;
3330 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3331 .function = sr_policy_rewrite_b_encaps,
3332 .name = "sr-pl-rewrite-b-encaps",
3333 .vector_size = sizeof (u32),
3334 .format_trace = format_sr_policy_rewrite_trace,
3335 .type = VLIB_NODE_TYPE_INTERNAL,
3336 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3337 .error_strings = sr_policy_rewrite_error_strings,
3338 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3340 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3341 foreach_sr_policy_rewrite_next
3347 /*************************** SR Policy plugins ******************************/
3349 * @brief SR Policy plugin registry
3352 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3353 u8 * keyword_str, u8 * def_str,
3354 u8 * params_str, u8 prefix_length,
3356 format_function_t * ls_format,
3357 unformat_function_t * ls_unformat,
3358 sr_p_plugin_callback_t * creation_fn,
3359 sr_p_plugin_callback_t * removal_fn)
3361 ip6_sr_main_t *sm = &sr_main;
3364 sr_policy_fn_registration_t *plugin;
3366 /* Did this function exist? If so update it */
3367 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3370 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3372 /* Else create a new one and set hash key */
3375 pool_get (sm->policy_plugin_functions, plugin);
3376 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3377 plugin - sm->policy_plugin_functions);
3380 clib_memset (plugin, 0, sizeof (*plugin));
3382 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3383 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3384 plugin->prefix_length = prefix_length;
3385 plugin->ls_format = ls_format;
3386 plugin->ls_unformat = ls_unformat;
3387 plugin->creation = creation_fn;
3388 plugin->removal = removal_fn;
3389 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3390 plugin->function_name = format (0, "%s%c", fn_name, 0);
3391 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3392 plugin->def_str = format (0, "%s%c", def_str, 0);
3393 plugin->params_str = format (0, "%s%c", params_str, 0);
3395 return plugin->sr_policy_function_number;
3399 * @brief CLI function to 'show' all available SR LocalSID behaviors
3401 static clib_error_t *
3402 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3403 unformat_input_t * input,
3404 vlib_cli_command_t * cmd)
3406 ip6_sr_main_t *sm = &sr_main;
3407 sr_policy_fn_registration_t *plugin;
3408 sr_policy_fn_registration_t **plugins_vec = 0;
3411 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3414 pool_foreach (plugin, sm->policy_plugin_functions)
3415 { vec_add1 (plugins_vec, plugin); }
3418 vlib_cli_output (vm, "Plugin behaviors:\n");
3419 for (i = 0; i < vec_len (plugins_vec); i++)
3421 plugin = plugins_vec[i];
3422 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3424 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3430 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3431 .path = "show sr policy behaviors",
3432 .short_help = "show sr policy behaviors",
3433 .function = show_sr_policy_behaviors_command_fn,
3437 /*************************** SR Segment Lists DPOs ****************************/
3439 format_sr_segment_list_dpo (u8 * s, va_list * args)
3441 ip6_sr_main_t *sm = &sr_main;
3442 ip6_address_t *addr;
3445 index_t index = va_arg (*args, index_t);
3446 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3447 s = format (s, "SR: Segment List index:[%d]", index);
3448 s = format (s, "\n\tSegments:");
3450 sl = pool_elt_at_index (sm->sid_lists, index);
3452 s = format (s, "< ");
3453 vec_foreach (addr, sl->segments)
3455 s = format (s, "%U, ", format_ip6_address, addr);
3457 s = format (s, "\b\b > - ");
3458 s = format (s, "Weight: %u", sl->weight);
3463 const static dpo_vft_t sr_policy_rewrite_vft = {
3464 .dv_lock = sr_dpo_lock,
3465 .dv_unlock = sr_dpo_unlock,
3466 .dv_format = format_sr_segment_list_dpo,
3469 const static char *const sr_pr_encaps_ip6_nodes[] = {
3470 "sr-pl-rewrite-encaps",
3474 const static char *const sr_pr_encaps_ip4_nodes[] = {
3475 "sr-pl-rewrite-encaps-v4",
3479 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3480 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3481 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3484 const static char *const sr_pr_insert_ip6_nodes[] = {
3485 "sr-pl-rewrite-insert",
3489 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3490 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3493 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3494 "sr-pl-rewrite-b-insert",
3498 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3499 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3502 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3503 "sr-pl-rewrite-b-encaps",
3507 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3508 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3511 /********************* SR Policy Rewrite initialization ***********************/
3513 * @brief SR Policy Rewrite initialization
3516 sr_policy_rewrite_init (vlib_main_t * vm)
3518 ip6_sr_main_t *sm = &sr_main;
3520 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3521 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3522 sizeof (ip6_address_t));
3524 /* Init SR VPO DPOs type */
3525 sr_pr_encaps_dpo_type =
3526 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3528 sr_pr_insert_dpo_type =
3529 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3531 sr_pr_bsid_encaps_dpo_type =
3532 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3534 sr_pr_bsid_insert_dpo_type =
3535 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3537 /* Register the L2 encaps node used in HW redirect */
3538 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3540 sm->fib_table_ip6 = (u32) ~ 0;
3541 sm->fib_table_ip4 = (u32) ~ 0;
3546 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3550 * fd.io coding-style-patch-verification: ON
3553 * eval: (c-set-style "gnu")