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,
1192 /*************************** SR rewrite graph node ****************************/
1194 * @brief Trace for the SR Policy Rewrite graph node
1197 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1200 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1201 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1202 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1205 (s, "SR-policy-rewrite: src %U dst %U",
1206 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1212 * @brief IPv6 encapsulation processing as per RFC2473
1214 static_always_inline void
1215 encaps_processing_v6 (vlib_node_runtime_t * node,
1217 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1221 ip0_encap->hop_limit -= 1;
1223 ip0->payload_length + sizeof (ip6_header_t) +
1224 clib_net_to_host_u16 (ip0_encap->payload_length);
1225 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1226 ip0->ip_version_traffic_class_and_flow_label =
1227 ip0_encap->ip_version_traffic_class_and_flow_label;
1231 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1234 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1235 vlib_frame_t * from_frame)
1237 ip6_sr_main_t *sm = &sr_main;
1238 u32 n_left_from, next_index, *from, *to_next;
1240 from = vlib_frame_vector_args (from_frame);
1241 n_left_from = from_frame->n_vectors;
1243 next_index = node->cached_next_index;
1245 int encap_pkts = 0, bsid_pkts = 0;
1247 while (n_left_from > 0)
1251 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1254 while (n_left_from >= 8 && n_left_to_next >= 4)
1256 u32 bi0, bi1, bi2, bi3;
1257 vlib_buffer_t *b0, *b1, *b2, *b3;
1258 u32 next0, next1, next2, next3;
1259 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1260 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1261 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1262 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1264 /* Prefetch next iteration. */
1266 vlib_buffer_t *p4, *p5, *p6, *p7;
1268 p4 = vlib_get_buffer (vm, from[4]);
1269 p5 = vlib_get_buffer (vm, from[5]);
1270 p6 = vlib_get_buffer (vm, from[6]);
1271 p7 = vlib_get_buffer (vm, from[7]);
1273 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1274 vlib_prefetch_buffer_header (p4, LOAD);
1275 vlib_prefetch_buffer_header (p5, LOAD);
1276 vlib_prefetch_buffer_header (p6, LOAD);
1277 vlib_prefetch_buffer_header (p7, LOAD);
1279 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1280 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1281 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1282 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1285 to_next[0] = bi0 = from[0];
1286 to_next[1] = bi1 = from[1];
1287 to_next[2] = bi2 = from[2];
1288 to_next[3] = bi3 = from[3];
1292 n_left_to_next -= 4;
1294 b0 = vlib_get_buffer (vm, bi0);
1295 b1 = vlib_get_buffer (vm, bi1);
1296 b2 = vlib_get_buffer (vm, bi2);
1297 b3 = vlib_get_buffer (vm, bi3);
1300 pool_elt_at_index (sm->sid_lists,
1301 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1303 pool_elt_at_index (sm->sid_lists,
1304 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1306 pool_elt_at_index (sm->sid_lists,
1307 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1309 pool_elt_at_index (sm->sid_lists,
1310 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1312 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1313 vec_len (sl0->rewrite));
1314 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1315 vec_len (sl1->rewrite));
1316 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1317 vec_len (sl2->rewrite));
1318 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1319 vec_len (sl3->rewrite));
1321 ip0_encap = vlib_buffer_get_current (b0);
1322 ip1_encap = vlib_buffer_get_current (b1);
1323 ip2_encap = vlib_buffer_get_current (b2);
1324 ip3_encap = vlib_buffer_get_current (b3);
1326 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1327 sl0->rewrite, vec_len (sl0->rewrite));
1328 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1329 sl1->rewrite, vec_len (sl1->rewrite));
1330 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1331 sl2->rewrite, vec_len (sl2->rewrite));
1332 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1333 sl3->rewrite, vec_len (sl3->rewrite));
1335 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1336 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1337 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1338 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1340 ip0 = vlib_buffer_get_current (b0);
1341 ip1 = vlib_buffer_get_current (b1);
1342 ip2 = vlib_buffer_get_current (b2);
1343 ip3 = vlib_buffer_get_current (b3);
1345 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1346 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1347 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1348 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1350 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1352 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1354 sr_policy_rewrite_trace_t *tr =
1355 vlib_add_trace (vm, node, b0, sizeof (*tr));
1356 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1357 sizeof (tr->src.as_u8));
1358 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1359 sizeof (tr->dst.as_u8));
1362 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1364 sr_policy_rewrite_trace_t *tr =
1365 vlib_add_trace (vm, node, b1, sizeof (*tr));
1366 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1367 sizeof (tr->src.as_u8));
1368 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1369 sizeof (tr->dst.as_u8));
1372 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1374 sr_policy_rewrite_trace_t *tr =
1375 vlib_add_trace (vm, node, b2, sizeof (*tr));
1376 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1377 sizeof (tr->src.as_u8));
1378 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1379 sizeof (tr->dst.as_u8));
1382 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1384 sr_policy_rewrite_trace_t *tr =
1385 vlib_add_trace (vm, node, b3, sizeof (*tr));
1386 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1387 sizeof (tr->src.as_u8));
1388 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1389 sizeof (tr->dst.as_u8));
1394 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1395 n_left_to_next, bi0, bi1, bi2, bi3,
1396 next0, next1, next2, next3);
1399 /* Single loop for potentially the last three packets */
1400 while (n_left_from > 0 && n_left_to_next > 0)
1404 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1406 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1413 n_left_to_next -= 1;
1414 b0 = vlib_get_buffer (vm, bi0);
1417 pool_elt_at_index (sm->sid_lists,
1418 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1419 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1420 vec_len (sl0->rewrite));
1422 ip0_encap = vlib_buffer_get_current (b0);
1424 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1425 sl0->rewrite, vec_len (sl0->rewrite));
1426 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1428 ip0 = vlib_buffer_get_current (b0);
1430 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1432 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1433 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1435 sr_policy_rewrite_trace_t *tr =
1436 vlib_add_trace (vm, node, b0, sizeof (*tr));
1437 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1438 sizeof (tr->src.as_u8));
1439 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1440 sizeof (tr->dst.as_u8));
1444 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1445 n_left_to_next, bi0, next0);
1448 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1451 /* Update counters */
1452 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1453 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1455 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1456 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1459 return from_frame->n_vectors;
1463 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1464 .function = sr_policy_rewrite_encaps,
1465 .name = "sr-pl-rewrite-encaps",
1466 .vector_size = sizeof (u32),
1467 .format_trace = format_sr_policy_rewrite_trace,
1468 .type = VLIB_NODE_TYPE_INTERNAL,
1469 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1470 .error_strings = sr_policy_rewrite_error_strings,
1471 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1473 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1474 foreach_sr_policy_rewrite_next
1481 * @brief IPv4 encapsulation processing as per RFC2473
1483 static_always_inline void
1484 encaps_processing_v4 (vlib_node_runtime_t * node,
1486 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1489 ip6_sr_header_t *sr0;
1493 /* Inner IPv4: Decrement TTL & update checksum */
1494 ip0_encap->ttl -= 1;
1495 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1496 checksum0 += checksum0 >= 0xffff;
1497 ip0_encap->checksum = checksum0;
1499 /* Outer IPv6: Update length, FL, proto */
1500 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1501 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1502 ip0->ip_version_traffic_class_and_flow_label =
1503 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1504 ((ip0_encap->tos & 0xFF) << 20));
1505 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1507 sr0 = (void *) (ip0 + 1);
1508 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1511 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1515 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1518 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1519 vlib_frame_t * from_frame)
1521 ip6_sr_main_t *sm = &sr_main;
1522 u32 n_left_from, next_index, *from, *to_next;
1524 from = vlib_frame_vector_args (from_frame);
1525 n_left_from = from_frame->n_vectors;
1527 next_index = node->cached_next_index;
1529 int encap_pkts = 0, bsid_pkts = 0;
1531 while (n_left_from > 0)
1535 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1538 while (n_left_from >= 8 && n_left_to_next >= 4)
1540 u32 bi0, bi1, bi2, bi3;
1541 vlib_buffer_t *b0, *b1, *b2, *b3;
1542 u32 next0, next1, next2, next3;
1543 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1544 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1545 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1546 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1548 /* Prefetch next iteration. */
1550 vlib_buffer_t *p4, *p5, *p6, *p7;
1552 p4 = vlib_get_buffer (vm, from[4]);
1553 p5 = vlib_get_buffer (vm, from[5]);
1554 p6 = vlib_get_buffer (vm, from[6]);
1555 p7 = vlib_get_buffer (vm, from[7]);
1557 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1558 vlib_prefetch_buffer_header (p4, LOAD);
1559 vlib_prefetch_buffer_header (p5, LOAD);
1560 vlib_prefetch_buffer_header (p6, LOAD);
1561 vlib_prefetch_buffer_header (p7, LOAD);
1563 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1564 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1565 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1566 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1569 to_next[0] = bi0 = from[0];
1570 to_next[1] = bi1 = from[1];
1571 to_next[2] = bi2 = from[2];
1572 to_next[3] = bi3 = from[3];
1576 n_left_to_next -= 4;
1578 b0 = vlib_get_buffer (vm, bi0);
1579 b1 = vlib_get_buffer (vm, bi1);
1580 b2 = vlib_get_buffer (vm, bi2);
1581 b3 = vlib_get_buffer (vm, bi3);
1584 pool_elt_at_index (sm->sid_lists,
1585 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1587 pool_elt_at_index (sm->sid_lists,
1588 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1590 pool_elt_at_index (sm->sid_lists,
1591 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1593 pool_elt_at_index (sm->sid_lists,
1594 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1595 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1596 vec_len (sl0->rewrite));
1597 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1598 vec_len (sl1->rewrite));
1599 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1600 vec_len (sl2->rewrite));
1601 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1602 vec_len (sl3->rewrite));
1604 ip0_encap = vlib_buffer_get_current (b0);
1605 ip1_encap = vlib_buffer_get_current (b1);
1606 ip2_encap = vlib_buffer_get_current (b2);
1607 ip3_encap = vlib_buffer_get_current (b3);
1609 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1610 sl0->rewrite, vec_len (sl0->rewrite));
1611 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1612 sl1->rewrite, vec_len (sl1->rewrite));
1613 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1614 sl2->rewrite, vec_len (sl2->rewrite));
1615 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1616 sl3->rewrite, vec_len (sl3->rewrite));
1618 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1619 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1620 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1621 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1623 ip0 = vlib_buffer_get_current (b0);
1624 ip1 = vlib_buffer_get_current (b1);
1625 ip2 = vlib_buffer_get_current (b2);
1626 ip3 = vlib_buffer_get_current (b3);
1628 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1629 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1630 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1631 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1633 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1635 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1637 sr_policy_rewrite_trace_t *tr =
1638 vlib_add_trace (vm, node, b0, sizeof (*tr));
1639 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1640 sizeof (tr->src.as_u8));
1641 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1642 sizeof (tr->dst.as_u8));
1645 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1647 sr_policy_rewrite_trace_t *tr =
1648 vlib_add_trace (vm, node, b1, sizeof (*tr));
1649 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1650 sizeof (tr->src.as_u8));
1651 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1652 sizeof (tr->dst.as_u8));
1655 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1657 sr_policy_rewrite_trace_t *tr =
1658 vlib_add_trace (vm, node, b2, sizeof (*tr));
1659 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1660 sizeof (tr->src.as_u8));
1661 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1662 sizeof (tr->dst.as_u8));
1665 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1667 sr_policy_rewrite_trace_t *tr =
1668 vlib_add_trace (vm, node, b3, sizeof (*tr));
1669 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1670 sizeof (tr->src.as_u8));
1671 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1672 sizeof (tr->dst.as_u8));
1677 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1678 n_left_to_next, bi0, bi1, bi2, bi3,
1679 next0, next1, next2, next3);
1682 /* Single loop for potentially the last three packets */
1683 while (n_left_from > 0 && n_left_to_next > 0)
1687 ip6_header_t *ip0 = 0;
1688 ip4_header_t *ip0_encap = 0;
1690 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1697 n_left_to_next -= 1;
1698 b0 = vlib_get_buffer (vm, bi0);
1701 pool_elt_at_index (sm->sid_lists,
1702 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1703 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1704 vec_len (sl0->rewrite));
1706 ip0_encap = vlib_buffer_get_current (b0);
1708 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1709 sl0->rewrite, vec_len (sl0->rewrite));
1710 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1712 ip0 = vlib_buffer_get_current (b0);
1714 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1716 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1717 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1719 sr_policy_rewrite_trace_t *tr =
1720 vlib_add_trace (vm, node, b0, sizeof (*tr));
1721 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1722 sizeof (tr->src.as_u8));
1723 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1724 sizeof (tr->dst.as_u8));
1728 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1729 n_left_to_next, bi0, next0);
1732 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1735 /* Update counters */
1736 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1737 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1739 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1740 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1743 return from_frame->n_vectors;
1747 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1748 .function = sr_policy_rewrite_encaps_v4,
1749 .name = "sr-pl-rewrite-encaps-v4",
1750 .vector_size = sizeof (u32),
1751 .format_trace = format_sr_policy_rewrite_trace,
1752 .type = VLIB_NODE_TYPE_INTERNAL,
1753 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1754 .error_strings = sr_policy_rewrite_error_strings,
1755 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1757 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1758 foreach_sr_policy_rewrite_next
1765 ip_flow_hash (void *data)
1767 ip4_header_t *iph = (ip4_header_t *) data;
1769 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1770 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1772 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1778 return (*((u64 *) m) & 0xffffffffffff);
1782 l2_flow_hash (vlib_buffer_t * b0)
1784 ethernet_header_t *eh;
1786 uword is_ip, eh_size;
1789 eh = vlib_buffer_get_current (b0);
1790 eh_type = clib_net_to_host_u16 (eh->type);
1791 eh_size = ethernet_buffer_header_size (b0);
1793 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1795 /* since we have 2 cache lines, use them */
1797 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1801 b = mac_to_u64 ((u8 *) eh->dst_address);
1802 c = mac_to_u64 ((u8 *) eh->src_address);
1803 hash_mix64 (a, b, c);
1809 * @brief Graph node for applying a SR policy into a L2 frame
1812 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1813 vlib_frame_t * from_frame)
1815 ip6_sr_main_t *sm = &sr_main;
1816 u32 n_left_from, next_index, *from, *to_next;
1818 from = vlib_frame_vector_args (from_frame);
1819 n_left_from = from_frame->n_vectors;
1821 next_index = node->cached_next_index;
1823 int encap_pkts = 0, bsid_pkts = 0;
1825 while (n_left_from > 0)
1829 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1832 while (n_left_from >= 8 && n_left_to_next >= 4)
1834 u32 bi0, bi1, bi2, bi3;
1835 vlib_buffer_t *b0, *b1, *b2, *b3;
1836 u32 next0, next1, next2, next3;
1837 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1838 ethernet_header_t *en0, *en1, *en2, *en3;
1839 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1840 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1841 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1842 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1844 /* Prefetch next iteration. */
1846 vlib_buffer_t *p4, *p5, *p6, *p7;
1848 p4 = vlib_get_buffer (vm, from[4]);
1849 p5 = vlib_get_buffer (vm, from[5]);
1850 p6 = vlib_get_buffer (vm, from[6]);
1851 p7 = vlib_get_buffer (vm, from[7]);
1853 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1854 vlib_prefetch_buffer_header (p4, LOAD);
1855 vlib_prefetch_buffer_header (p5, LOAD);
1856 vlib_prefetch_buffer_header (p6, LOAD);
1857 vlib_prefetch_buffer_header (p7, LOAD);
1859 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1860 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1861 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1862 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1865 to_next[0] = bi0 = from[0];
1866 to_next[1] = bi1 = from[1];
1867 to_next[2] = bi2 = from[2];
1868 to_next[3] = bi3 = from[3];
1872 n_left_to_next -= 4;
1874 b0 = vlib_get_buffer (vm, bi0);
1875 b1 = vlib_get_buffer (vm, bi1);
1876 b2 = vlib_get_buffer (vm, bi2);
1877 b3 = vlib_get_buffer (vm, bi3);
1879 sp0 = pool_elt_at_index (sm->sr_policies,
1880 sm->sw_iface_sr_policies[vnet_buffer
1884 sp1 = pool_elt_at_index (sm->sr_policies,
1885 sm->sw_iface_sr_policies[vnet_buffer
1889 sp2 = pool_elt_at_index (sm->sr_policies,
1890 sm->sw_iface_sr_policies[vnet_buffer
1894 sp3 = pool_elt_at_index (sm->sr_policies,
1895 sm->sw_iface_sr_policies[vnet_buffer
1899 if (vec_len (sp0->segments_lists) == 1)
1900 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1903 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1904 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1905 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1906 (vec_len (sp0->segments_lists) - 1))];
1909 if (vec_len (sp1->segments_lists) == 1)
1910 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1913 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1914 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1915 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1916 (vec_len (sp1->segments_lists) - 1))];
1919 if (vec_len (sp2->segments_lists) == 1)
1920 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1923 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1924 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1925 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1926 (vec_len (sp2->segments_lists) - 1))];
1929 if (vec_len (sp3->segments_lists) == 1)
1930 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1933 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1934 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1935 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1936 (vec_len (sp3->segments_lists) - 1))];
1940 pool_elt_at_index (sm->sid_lists,
1941 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1943 pool_elt_at_index (sm->sid_lists,
1944 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1946 pool_elt_at_index (sm->sid_lists,
1947 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1949 pool_elt_at_index (sm->sid_lists,
1950 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1952 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1953 vec_len (sl0->rewrite));
1954 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1955 vec_len (sl1->rewrite));
1956 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1957 vec_len (sl2->rewrite));
1958 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1959 vec_len (sl3->rewrite));
1961 en0 = vlib_buffer_get_current (b0);
1962 en1 = vlib_buffer_get_current (b1);
1963 en2 = vlib_buffer_get_current (b2);
1964 en3 = vlib_buffer_get_current (b3);
1966 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1967 sl0->rewrite, vec_len (sl0->rewrite));
1968 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1969 sl1->rewrite, vec_len (sl1->rewrite));
1970 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1971 sl2->rewrite, vec_len (sl2->rewrite));
1972 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1973 sl3->rewrite, vec_len (sl3->rewrite));
1975 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1976 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1977 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1978 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1980 ip0 = vlib_buffer_get_current (b0);
1981 ip1 = vlib_buffer_get_current (b1);
1982 ip2 = vlib_buffer_get_current (b2);
1983 ip3 = vlib_buffer_get_current (b3);
1985 ip0->payload_length =
1986 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1987 ip1->payload_length =
1988 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1989 ip2->payload_length =
1990 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1991 ip3->payload_length =
1992 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1994 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1996 sr0 = (void *) (ip0 + 1);
1997 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2000 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2002 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2004 sr1 = (void *) (ip1 + 1);
2005 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2008 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2010 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2012 sr2 = (void *) (ip2 + 1);
2013 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2016 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2018 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2020 sr3 = (void *) (ip3 + 1);
2021 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2024 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2026 /* Which Traffic class and flow label do I set ? */
2027 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2029 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2031 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2033 sr_policy_rewrite_trace_t *tr =
2034 vlib_add_trace (vm, node, b0, sizeof (*tr));
2035 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2036 sizeof (tr->src.as_u8));
2037 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2038 sizeof (tr->dst.as_u8));
2041 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2043 sr_policy_rewrite_trace_t *tr =
2044 vlib_add_trace (vm, node, b1, sizeof (*tr));
2045 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2046 sizeof (tr->src.as_u8));
2047 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2048 sizeof (tr->dst.as_u8));
2051 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2053 sr_policy_rewrite_trace_t *tr =
2054 vlib_add_trace (vm, node, b2, sizeof (*tr));
2055 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2056 sizeof (tr->src.as_u8));
2057 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2058 sizeof (tr->dst.as_u8));
2061 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2063 sr_policy_rewrite_trace_t *tr =
2064 vlib_add_trace (vm, node, b3, sizeof (*tr));
2065 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2066 sizeof (tr->src.as_u8));
2067 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2068 sizeof (tr->dst.as_u8));
2073 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2074 n_left_to_next, bi0, bi1, bi2, bi3,
2075 next0, next1, next2, next3);
2078 /* Single loop for potentially the last three packets */
2079 while (n_left_from > 0 && n_left_to_next > 0)
2083 ip6_header_t *ip0 = 0;
2084 ip6_sr_header_t *sr0;
2085 ethernet_header_t *en0;
2086 ip6_sr_policy_t *sp0;
2088 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2095 n_left_to_next -= 1;
2096 b0 = vlib_get_buffer (vm, bi0);
2098 /* Find the SR policy */
2099 sp0 = pool_elt_at_index (sm->sr_policies,
2100 sm->sw_iface_sr_policies[vnet_buffer
2104 /* In case there is more than one SL, LB among them */
2105 if (vec_len (sp0->segments_lists) == 1)
2106 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2109 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2110 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2111 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2112 (vec_len (sp0->segments_lists) - 1))];
2115 pool_elt_at_index (sm->sid_lists,
2116 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2117 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2118 vec_len (sl0->rewrite));
2120 en0 = vlib_buffer_get_current (b0);
2122 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2123 sl0->rewrite, vec_len (sl0->rewrite));
2125 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2127 ip0 = vlib_buffer_get_current (b0);
2129 ip0->payload_length =
2130 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2132 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2134 sr0 = (void *) (ip0 + 1);
2135 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2138 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2140 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2141 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2143 sr_policy_rewrite_trace_t *tr =
2144 vlib_add_trace (vm, node, b0, sizeof (*tr));
2145 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2146 sizeof (tr->src.as_u8));
2147 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2148 sizeof (tr->dst.as_u8));
2152 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2153 n_left_to_next, bi0, next0);
2156 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2159 /* Update counters */
2160 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2161 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2163 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2164 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2167 return from_frame->n_vectors;
2171 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2172 .function = sr_policy_rewrite_encaps_l2,
2173 .name = "sr-pl-rewrite-encaps-l2",
2174 .vector_size = sizeof (u32),
2175 .format_trace = format_sr_policy_rewrite_trace,
2176 .type = VLIB_NODE_TYPE_INTERNAL,
2177 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2178 .error_strings = sr_policy_rewrite_error_strings,
2179 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2181 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2182 foreach_sr_policy_rewrite_next
2189 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2192 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2193 vlib_frame_t * from_frame)
2195 ip6_sr_main_t *sm = &sr_main;
2196 u32 n_left_from, next_index, *from, *to_next;
2198 from = vlib_frame_vector_args (from_frame);
2199 n_left_from = from_frame->n_vectors;
2201 next_index = node->cached_next_index;
2203 int insert_pkts = 0, bsid_pkts = 0;
2205 while (n_left_from > 0)
2209 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2212 while (n_left_from >= 8 && n_left_to_next >= 4)
2214 u32 bi0, bi1, bi2, bi3;
2215 vlib_buffer_t *b0, *b1, *b2, *b3;
2216 u32 next0, next1, next2, next3;
2217 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2218 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2219 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2220 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2221 u16 new_l0, new_l1, new_l2, new_l3;
2223 /* Prefetch next iteration. */
2225 vlib_buffer_t *p4, *p5, *p6, *p7;
2227 p4 = vlib_get_buffer (vm, from[4]);
2228 p5 = vlib_get_buffer (vm, from[5]);
2229 p6 = vlib_get_buffer (vm, from[6]);
2230 p7 = vlib_get_buffer (vm, from[7]);
2232 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2233 vlib_prefetch_buffer_header (p4, LOAD);
2234 vlib_prefetch_buffer_header (p5, LOAD);
2235 vlib_prefetch_buffer_header (p6, LOAD);
2236 vlib_prefetch_buffer_header (p7, LOAD);
2238 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2239 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2240 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2241 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2244 to_next[0] = bi0 = from[0];
2245 to_next[1] = bi1 = from[1];
2246 to_next[2] = bi2 = from[2];
2247 to_next[3] = bi3 = from[3];
2251 n_left_to_next -= 4;
2253 b0 = vlib_get_buffer (vm, bi0);
2254 b1 = vlib_get_buffer (vm, bi1);
2255 b2 = vlib_get_buffer (vm, bi2);
2256 b3 = vlib_get_buffer (vm, bi3);
2259 pool_elt_at_index (sm->sid_lists,
2260 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2262 pool_elt_at_index (sm->sid_lists,
2263 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2265 pool_elt_at_index (sm->sid_lists,
2266 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2268 pool_elt_at_index (sm->sid_lists,
2269 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2270 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2271 vec_len (sl0->rewrite));
2272 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2273 vec_len (sl1->rewrite));
2274 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2275 vec_len (sl2->rewrite));
2276 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2277 vec_len (sl3->rewrite));
2279 ip0 = vlib_buffer_get_current (b0);
2280 ip1 = vlib_buffer_get_current (b1);
2281 ip2 = vlib_buffer_get_current (b2);
2282 ip3 = vlib_buffer_get_current (b3);
2284 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2286 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2287 ip6_ext_header_len (ip0 + 1));
2289 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2291 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2293 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2294 ip6_ext_header_len (ip1 + 1));
2296 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2298 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2300 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2301 ip6_ext_header_len (ip2 + 1));
2303 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2305 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2307 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2308 ip6_ext_header_len (ip3 + 1));
2310 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2312 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2313 (void *) sr0 - (void *) ip0);
2314 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2315 (void *) sr1 - (void *) ip1);
2316 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2317 (void *) sr2 - (void *) ip2);
2318 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2319 (void *) sr3 - (void *) ip3);
2321 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2322 sl0->rewrite, vec_len (sl0->rewrite));
2323 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2324 sl1->rewrite, vec_len (sl1->rewrite));
2325 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2326 sl2->rewrite, vec_len (sl2->rewrite));
2327 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2328 sl3->rewrite, vec_len (sl3->rewrite));
2330 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2331 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2332 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2333 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2335 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2336 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2337 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2338 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2340 ip0->hop_limit -= 1;
2341 ip1->hop_limit -= 1;
2342 ip2->hop_limit -= 1;
2343 ip3->hop_limit -= 1;
2346 clib_net_to_host_u16 (ip0->payload_length) +
2347 vec_len (sl0->rewrite);
2349 clib_net_to_host_u16 (ip1->payload_length) +
2350 vec_len (sl1->rewrite);
2352 clib_net_to_host_u16 (ip2->payload_length) +
2353 vec_len (sl2->rewrite);
2355 clib_net_to_host_u16 (ip3->payload_length) +
2356 vec_len (sl3->rewrite);
2358 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2359 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2360 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2361 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2363 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2364 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2365 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2366 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2368 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2369 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2370 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2371 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2372 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2373 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2374 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2375 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2377 ip0->dst_address.as_u64[0] =
2378 (sr0->segments + sr0->segments_left)->as_u64[0];
2379 ip0->dst_address.as_u64[1] =
2380 (sr0->segments + sr0->segments_left)->as_u64[1];
2381 ip1->dst_address.as_u64[0] =
2382 (sr1->segments + sr1->segments_left)->as_u64[0];
2383 ip1->dst_address.as_u64[1] =
2384 (sr1->segments + sr1->segments_left)->as_u64[1];
2385 ip2->dst_address.as_u64[0] =
2386 (sr2->segments + sr2->segments_left)->as_u64[0];
2387 ip2->dst_address.as_u64[1] =
2388 (sr2->segments + sr2->segments_left)->as_u64[1];
2389 ip3->dst_address.as_u64[0] =
2390 (sr3->segments + sr3->segments_left)->as_u64[0];
2391 ip3->dst_address.as_u64[1] =
2392 (sr3->segments + sr3->segments_left)->as_u64[1];
2394 ip6_ext_header_t *ip_ext;
2395 if (ip0 + 1 == (void *) sr0)
2397 sr0->protocol = ip0->protocol;
2398 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2402 ip_ext = (void *) (ip0 + 1);
2403 sr0->protocol = ip_ext->next_hdr;
2404 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2407 if (ip1 + 1 == (void *) sr1)
2409 sr1->protocol = ip1->protocol;
2410 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2414 ip_ext = (void *) (ip2 + 1);
2415 sr2->protocol = ip_ext->next_hdr;
2416 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2419 if (ip2 + 1 == (void *) sr2)
2421 sr2->protocol = ip2->protocol;
2422 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2426 ip_ext = (void *) (ip2 + 1);
2427 sr2->protocol = ip_ext->next_hdr;
2428 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2431 if (ip3 + 1 == (void *) sr3)
2433 sr3->protocol = ip3->protocol;
2434 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2438 ip_ext = (void *) (ip3 + 1);
2439 sr3->protocol = ip_ext->next_hdr;
2440 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2445 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2447 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2449 sr_policy_rewrite_trace_t *tr =
2450 vlib_add_trace (vm, node, b0, sizeof (*tr));
2451 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2452 sizeof (tr->src.as_u8));
2453 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2454 sizeof (tr->dst.as_u8));
2457 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2459 sr_policy_rewrite_trace_t *tr =
2460 vlib_add_trace (vm, node, b1, sizeof (*tr));
2461 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2462 sizeof (tr->src.as_u8));
2463 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2464 sizeof (tr->dst.as_u8));
2467 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2469 sr_policy_rewrite_trace_t *tr =
2470 vlib_add_trace (vm, node, b2, sizeof (*tr));
2471 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2472 sizeof (tr->src.as_u8));
2473 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2474 sizeof (tr->dst.as_u8));
2477 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2479 sr_policy_rewrite_trace_t *tr =
2480 vlib_add_trace (vm, node, b3, sizeof (*tr));
2481 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2482 sizeof (tr->src.as_u8));
2483 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2484 sizeof (tr->dst.as_u8));
2488 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2489 n_left_to_next, bi0, bi1, bi2, bi3,
2490 next0, next1, next2, next3);
2493 /* Single loop for potentially the last three packets */
2494 while (n_left_from > 0 && n_left_to_next > 0)
2498 ip6_header_t *ip0 = 0;
2499 ip6_sr_header_t *sr0 = 0;
2501 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2509 n_left_to_next -= 1;
2511 b0 = vlib_get_buffer (vm, bi0);
2513 pool_elt_at_index (sm->sid_lists,
2514 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2515 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2516 vec_len (sl0->rewrite));
2518 ip0 = vlib_buffer_get_current (b0);
2520 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2522 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2523 ip6_ext_header_len (ip0 + 1));
2525 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2527 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2528 (void *) sr0 - (void *) ip0);
2529 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2530 sl0->rewrite, vec_len (sl0->rewrite));
2532 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2534 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2535 ip0->hop_limit -= 1;
2537 clib_net_to_host_u16 (ip0->payload_length) +
2538 vec_len (sl0->rewrite);
2539 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2541 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2542 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2543 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2545 ip0->dst_address.as_u64[0] =
2546 (sr0->segments + sr0->segments_left)->as_u64[0];
2547 ip0->dst_address.as_u64[1] =
2548 (sr0->segments + sr0->segments_left)->as_u64[1];
2550 if (ip0 + 1 == (void *) sr0)
2552 sr0->protocol = ip0->protocol;
2553 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2557 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2558 sr0->protocol = ip_ext->next_hdr;
2559 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2562 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2563 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2565 sr_policy_rewrite_trace_t *tr =
2566 vlib_add_trace (vm, node, b0, sizeof (*tr));
2567 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2568 sizeof (tr->src.as_u8));
2569 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2570 sizeof (tr->dst.as_u8));
2575 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2576 n_left_to_next, bi0, next0);
2579 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2582 /* Update counters */
2583 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2584 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2586 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2587 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2589 return from_frame->n_vectors;
2593 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2594 .function = sr_policy_rewrite_insert,
2595 .name = "sr-pl-rewrite-insert",
2596 .vector_size = sizeof (u32),
2597 .format_trace = format_sr_policy_rewrite_trace,
2598 .type = VLIB_NODE_TYPE_INTERNAL,
2599 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2600 .error_strings = sr_policy_rewrite_error_strings,
2601 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2603 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2604 foreach_sr_policy_rewrite_next
2611 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2614 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2615 vlib_frame_t * from_frame)
2617 ip6_sr_main_t *sm = &sr_main;
2618 u32 n_left_from, next_index, *from, *to_next;
2620 from = vlib_frame_vector_args (from_frame);
2621 n_left_from = from_frame->n_vectors;
2623 next_index = node->cached_next_index;
2625 int insert_pkts = 0, bsid_pkts = 0;
2627 while (n_left_from > 0)
2631 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2634 while (n_left_from >= 8 && n_left_to_next >= 4)
2636 u32 bi0, bi1, bi2, bi3;
2637 vlib_buffer_t *b0, *b1, *b2, *b3;
2638 u32 next0, next1, next2, next3;
2639 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2640 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2641 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2642 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2643 u16 new_l0, new_l1, new_l2, new_l3;
2645 /* Prefetch next iteration. */
2647 vlib_buffer_t *p4, *p5, *p6, *p7;
2649 p4 = vlib_get_buffer (vm, from[4]);
2650 p5 = vlib_get_buffer (vm, from[5]);
2651 p6 = vlib_get_buffer (vm, from[6]);
2652 p7 = vlib_get_buffer (vm, from[7]);
2654 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2655 vlib_prefetch_buffer_header (p4, LOAD);
2656 vlib_prefetch_buffer_header (p5, LOAD);
2657 vlib_prefetch_buffer_header (p6, LOAD);
2658 vlib_prefetch_buffer_header (p7, LOAD);
2660 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2661 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2662 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2663 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2666 to_next[0] = bi0 = from[0];
2667 to_next[1] = bi1 = from[1];
2668 to_next[2] = bi2 = from[2];
2669 to_next[3] = bi3 = from[3];
2673 n_left_to_next -= 4;
2675 b0 = vlib_get_buffer (vm, bi0);
2676 b1 = vlib_get_buffer (vm, bi1);
2677 b2 = vlib_get_buffer (vm, bi2);
2678 b3 = vlib_get_buffer (vm, bi3);
2681 pool_elt_at_index (sm->sid_lists,
2682 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2684 pool_elt_at_index (sm->sid_lists,
2685 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2687 pool_elt_at_index (sm->sid_lists,
2688 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2690 pool_elt_at_index (sm->sid_lists,
2691 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2692 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2693 vec_len (sl0->rewrite_bsid));
2694 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2695 vec_len (sl1->rewrite_bsid));
2696 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2697 vec_len (sl2->rewrite_bsid));
2698 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2699 vec_len (sl3->rewrite_bsid));
2701 ip0 = vlib_buffer_get_current (b0);
2702 ip1 = vlib_buffer_get_current (b1);
2703 ip2 = vlib_buffer_get_current (b2);
2704 ip3 = vlib_buffer_get_current (b3);
2706 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2708 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2709 ip6_ext_header_len (ip0 + 1));
2711 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2713 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2715 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2716 ip6_ext_header_len (ip1 + 1));
2718 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2720 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2722 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2723 ip6_ext_header_len (ip2 + 1));
2725 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2727 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2729 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2730 ip6_ext_header_len (ip3 + 1));
2732 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2734 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2735 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2736 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2737 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2738 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2739 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2740 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2741 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2743 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2744 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2745 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2746 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2747 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2748 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2749 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2750 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2752 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2753 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2754 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2755 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2757 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2758 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2759 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2760 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2762 ip0->hop_limit -= 1;
2763 ip1->hop_limit -= 1;
2764 ip2->hop_limit -= 1;
2765 ip3->hop_limit -= 1;
2768 clib_net_to_host_u16 (ip0->payload_length) +
2769 vec_len (sl0->rewrite_bsid);
2771 clib_net_to_host_u16 (ip1->payload_length) +
2772 vec_len (sl1->rewrite_bsid);
2774 clib_net_to_host_u16 (ip2->payload_length) +
2775 vec_len (sl2->rewrite_bsid);
2777 clib_net_to_host_u16 (ip3->payload_length) +
2778 vec_len (sl3->rewrite_bsid);
2780 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2781 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2782 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2783 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2785 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2786 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2787 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2788 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2790 ip0->dst_address.as_u64[0] =
2791 (sr0->segments + sr0->segments_left)->as_u64[0];
2792 ip0->dst_address.as_u64[1] =
2793 (sr0->segments + sr0->segments_left)->as_u64[1];
2794 ip1->dst_address.as_u64[0] =
2795 (sr1->segments + sr1->segments_left)->as_u64[0];
2796 ip1->dst_address.as_u64[1] =
2797 (sr1->segments + sr1->segments_left)->as_u64[1];
2798 ip2->dst_address.as_u64[0] =
2799 (sr2->segments + sr2->segments_left)->as_u64[0];
2800 ip2->dst_address.as_u64[1] =
2801 (sr2->segments + sr2->segments_left)->as_u64[1];
2802 ip3->dst_address.as_u64[0] =
2803 (sr3->segments + sr3->segments_left)->as_u64[0];
2804 ip3->dst_address.as_u64[1] =
2805 (sr3->segments + sr3->segments_left)->as_u64[1];
2807 ip6_ext_header_t *ip_ext;
2808 if (ip0 + 1 == (void *) sr0)
2810 sr0->protocol = ip0->protocol;
2811 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2815 ip_ext = (void *) (ip0 + 1);
2816 sr0->protocol = ip_ext->next_hdr;
2817 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2820 if (ip1 + 1 == (void *) sr1)
2822 sr1->protocol = ip1->protocol;
2823 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2827 ip_ext = (void *) (ip2 + 1);
2828 sr2->protocol = ip_ext->next_hdr;
2829 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2832 if (ip2 + 1 == (void *) sr2)
2834 sr2->protocol = ip2->protocol;
2835 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2839 ip_ext = (void *) (ip2 + 1);
2840 sr2->protocol = ip_ext->next_hdr;
2841 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2844 if (ip3 + 1 == (void *) sr3)
2846 sr3->protocol = ip3->protocol;
2847 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2851 ip_ext = (void *) (ip3 + 1);
2852 sr3->protocol = ip_ext->next_hdr;
2853 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2858 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2860 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2862 sr_policy_rewrite_trace_t *tr =
2863 vlib_add_trace (vm, node, b0, sizeof (*tr));
2864 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2865 sizeof (tr->src.as_u8));
2866 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2867 sizeof (tr->dst.as_u8));
2870 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2872 sr_policy_rewrite_trace_t *tr =
2873 vlib_add_trace (vm, node, b1, sizeof (*tr));
2874 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2875 sizeof (tr->src.as_u8));
2876 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2877 sizeof (tr->dst.as_u8));
2880 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2882 sr_policy_rewrite_trace_t *tr =
2883 vlib_add_trace (vm, node, b2, sizeof (*tr));
2884 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2885 sizeof (tr->src.as_u8));
2886 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2887 sizeof (tr->dst.as_u8));
2890 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2892 sr_policy_rewrite_trace_t *tr =
2893 vlib_add_trace (vm, node, b3, sizeof (*tr));
2894 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2895 sizeof (tr->src.as_u8));
2896 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2897 sizeof (tr->dst.as_u8));
2901 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2902 n_left_to_next, bi0, bi1, bi2, bi3,
2903 next0, next1, next2, next3);
2906 /* Single loop for potentially the last three packets */
2907 while (n_left_from > 0 && n_left_to_next > 0)
2911 ip6_header_t *ip0 = 0;
2912 ip6_sr_header_t *sr0 = 0;
2914 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2922 n_left_to_next -= 1;
2924 b0 = vlib_get_buffer (vm, bi0);
2926 pool_elt_at_index (sm->sid_lists,
2927 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2928 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929 vec_len (sl0->rewrite_bsid));
2931 ip0 = vlib_buffer_get_current (b0);
2933 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2935 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2936 ip6_ext_header_len (ip0 + 1));
2938 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2940 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2941 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2942 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2943 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2945 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2947 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2948 ip0->hop_limit -= 1;
2950 clib_net_to_host_u16 (ip0->payload_length) +
2951 vec_len (sl0->rewrite_bsid);
2952 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2954 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2956 ip0->dst_address.as_u64[0] =
2957 (sr0->segments + sr0->segments_left)->as_u64[0];
2958 ip0->dst_address.as_u64[1] =
2959 (sr0->segments + sr0->segments_left)->as_u64[1];
2961 if (ip0 + 1 == (void *) sr0)
2963 sr0->protocol = ip0->protocol;
2964 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2968 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2969 sr0->protocol = ip_ext->next_hdr;
2970 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2973 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2974 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2976 sr_policy_rewrite_trace_t *tr =
2977 vlib_add_trace (vm, node, b0, sizeof (*tr));
2978 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2979 sizeof (tr->src.as_u8));
2980 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2981 sizeof (tr->dst.as_u8));
2986 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2987 n_left_to_next, bi0, next0);
2990 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2993 /* Update counters */
2994 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2995 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2997 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2998 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3000 return from_frame->n_vectors;
3004 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3005 .function = sr_policy_rewrite_b_insert,
3006 .name = "sr-pl-rewrite-b-insert",
3007 .vector_size = sizeof (u32),
3008 .format_trace = format_sr_policy_rewrite_trace,
3009 .type = VLIB_NODE_TYPE_INTERNAL,
3010 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3011 .error_strings = sr_policy_rewrite_error_strings,
3012 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3014 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3015 foreach_sr_policy_rewrite_next
3022 * @brief Function BSID encapsulation
3024 static_always_inline void
3025 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3028 ip6_sr_header_t * sr0, u32 * next0)
3030 ip6_address_t *new_dst0;
3032 if (PREDICT_FALSE (!sr0))
3033 goto error_bsid_encaps;
3035 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3037 if (PREDICT_TRUE (sr0->segments_left != 0))
3039 sr0->segments_left -= 1;
3040 new_dst0 = (ip6_address_t *) (sr0->segments);
3041 new_dst0 += sr0->segments_left;
3042 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3043 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3049 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3050 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3054 * @brief Graph node for applying a SR policy BSID - Encapsulation
3057 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3058 vlib_frame_t * from_frame)
3060 ip6_sr_main_t *sm = &sr_main;
3061 u32 n_left_from, next_index, *from, *to_next;
3063 from = vlib_frame_vector_args (from_frame);
3064 n_left_from = from_frame->n_vectors;
3066 next_index = node->cached_next_index;
3068 int encap_pkts = 0, bsid_pkts = 0;
3070 while (n_left_from > 0)
3074 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3077 while (n_left_from >= 8 && n_left_to_next >= 4)
3079 u32 bi0, bi1, bi2, bi3;
3080 vlib_buffer_t *b0, *b1, *b2, *b3;
3081 u32 next0, next1, next2, next3;
3082 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3083 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3084 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3085 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3086 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3088 /* Prefetch next iteration. */
3090 vlib_buffer_t *p4, *p5, *p6, *p7;
3092 p4 = vlib_get_buffer (vm, from[4]);
3093 p5 = vlib_get_buffer (vm, from[5]);
3094 p6 = vlib_get_buffer (vm, from[6]);
3095 p7 = vlib_get_buffer (vm, from[7]);
3097 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3098 vlib_prefetch_buffer_header (p4, LOAD);
3099 vlib_prefetch_buffer_header (p5, LOAD);
3100 vlib_prefetch_buffer_header (p6, LOAD);
3101 vlib_prefetch_buffer_header (p7, LOAD);
3103 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3104 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3105 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3106 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3109 to_next[0] = bi0 = from[0];
3110 to_next[1] = bi1 = from[1];
3111 to_next[2] = bi2 = from[2];
3112 to_next[3] = bi3 = from[3];
3116 n_left_to_next -= 4;
3118 b0 = vlib_get_buffer (vm, bi0);
3119 b1 = vlib_get_buffer (vm, bi1);
3120 b2 = vlib_get_buffer (vm, bi2);
3121 b3 = vlib_get_buffer (vm, bi3);
3124 pool_elt_at_index (sm->sid_lists,
3125 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3127 pool_elt_at_index (sm->sid_lists,
3128 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3130 pool_elt_at_index (sm->sid_lists,
3131 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3133 pool_elt_at_index (sm->sid_lists,
3134 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3135 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3136 vec_len (sl0->rewrite));
3137 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3138 vec_len (sl1->rewrite));
3139 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3140 vec_len (sl2->rewrite));
3141 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3142 vec_len (sl3->rewrite));
3144 ip0_encap = vlib_buffer_get_current (b0);
3145 ip1_encap = vlib_buffer_get_current (b1);
3146 ip2_encap = vlib_buffer_get_current (b2);
3147 ip3_encap = vlib_buffer_get_current (b3);
3150 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3153 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3156 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3159 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3162 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3163 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3164 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3165 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3167 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3168 sl0->rewrite, vec_len (sl0->rewrite));
3169 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3170 sl1->rewrite, vec_len (sl1->rewrite));
3171 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3172 sl2->rewrite, vec_len (sl2->rewrite));
3173 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3174 sl3->rewrite, vec_len (sl3->rewrite));
3176 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3177 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3178 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3179 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3181 ip0 = vlib_buffer_get_current (b0);
3182 ip1 = vlib_buffer_get_current (b1);
3183 ip2 = vlib_buffer_get_current (b2);
3184 ip3 = vlib_buffer_get_current (b3);
3186 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3187 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3188 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3189 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3191 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3193 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3195 sr_policy_rewrite_trace_t *tr =
3196 vlib_add_trace (vm, node, b0, sizeof (*tr));
3197 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3198 sizeof (tr->src.as_u8));
3199 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3200 sizeof (tr->dst.as_u8));
3203 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3205 sr_policy_rewrite_trace_t *tr =
3206 vlib_add_trace (vm, node, b1, sizeof (*tr));
3207 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3208 sizeof (tr->src.as_u8));
3209 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3210 sizeof (tr->dst.as_u8));
3213 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3215 sr_policy_rewrite_trace_t *tr =
3216 vlib_add_trace (vm, node, b2, sizeof (*tr));
3217 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3218 sizeof (tr->src.as_u8));
3219 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3220 sizeof (tr->dst.as_u8));
3223 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3225 sr_policy_rewrite_trace_t *tr =
3226 vlib_add_trace (vm, node, b3, sizeof (*tr));
3227 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3228 sizeof (tr->src.as_u8));
3229 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3230 sizeof (tr->dst.as_u8));
3235 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3236 n_left_to_next, bi0, bi1, bi2, bi3,
3237 next0, next1, next2, next3);
3240 /* Single loop for potentially the last three packets */
3241 while (n_left_from > 0 && n_left_to_next > 0)
3245 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3246 ip6_sr_header_t *sr0;
3248 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3255 n_left_to_next -= 1;
3256 b0 = vlib_get_buffer (vm, bi0);
3259 pool_elt_at_index (sm->sid_lists,
3260 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3261 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3262 vec_len (sl0->rewrite));
3264 ip0_encap = vlib_buffer_get_current (b0);
3266 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3268 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3270 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3271 sl0->rewrite, vec_len (sl0->rewrite));
3272 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3274 ip0 = vlib_buffer_get_current (b0);
3276 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3278 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3279 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3281 sr_policy_rewrite_trace_t *tr =
3282 vlib_add_trace (vm, node, b0, sizeof (*tr));
3283 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3284 sizeof (tr->src.as_u8));
3285 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3286 sizeof (tr->dst.as_u8));
3290 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3291 n_left_to_next, bi0, next0);
3294 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3297 /* Update counters */
3298 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3299 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3301 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3302 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3305 return from_frame->n_vectors;
3309 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3310 .function = sr_policy_rewrite_b_encaps,
3311 .name = "sr-pl-rewrite-b-encaps",
3312 .vector_size = sizeof (u32),
3313 .format_trace = format_sr_policy_rewrite_trace,
3314 .type = VLIB_NODE_TYPE_INTERNAL,
3315 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3316 .error_strings = sr_policy_rewrite_error_strings,
3317 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3319 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3320 foreach_sr_policy_rewrite_next
3326 /*************************** SR Policy plugins ******************************/
3328 * @brief SR Policy plugin registry
3331 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3332 u8 * keyword_str, u8 * def_str,
3333 u8 * params_str, u8 prefix_length,
3335 format_function_t * ls_format,
3336 unformat_function_t * ls_unformat,
3337 sr_p_plugin_callback_t * creation_fn,
3338 sr_p_plugin_callback_t * removal_fn)
3340 ip6_sr_main_t *sm = &sr_main;
3343 sr_policy_fn_registration_t *plugin;
3345 /* Did this function exist? If so update it */
3346 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3349 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3351 /* Else create a new one and set hash key */
3354 pool_get (sm->policy_plugin_functions, plugin);
3355 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3356 plugin - sm->policy_plugin_functions);
3359 clib_memset (plugin, 0, sizeof (*plugin));
3361 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3362 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3363 plugin->prefix_length = prefix_length;
3364 plugin->ls_format = ls_format;
3365 plugin->ls_unformat = ls_unformat;
3366 plugin->creation = creation_fn;
3367 plugin->removal = removal_fn;
3368 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3369 plugin->function_name = format (0, "%s%c", fn_name, 0);
3370 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3371 plugin->def_str = format (0, "%s%c", def_str, 0);
3372 plugin->params_str = format (0, "%s%c", params_str, 0);
3374 return plugin->sr_policy_function_number;
3378 * @brief CLI function to 'show' all available SR LocalSID behaviors
3380 static clib_error_t *
3381 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3382 unformat_input_t * input,
3383 vlib_cli_command_t * cmd)
3385 ip6_sr_main_t *sm = &sr_main;
3386 sr_policy_fn_registration_t *plugin;
3387 sr_policy_fn_registration_t **plugins_vec = 0;
3390 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3393 pool_foreach (plugin, sm->policy_plugin_functions,
3394 ({ vec_add1 (plugins_vec, plugin); }));
3397 vlib_cli_output (vm, "Plugin behaviors:\n");
3398 for (i = 0; i < vec_len (plugins_vec); i++)
3400 plugin = plugins_vec[i];
3401 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3403 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3409 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3410 .path = "show sr policy behaviors",
3411 .short_help = "show sr policy behaviors",
3412 .function = show_sr_policy_behaviors_command_fn,
3416 /*************************** SR Segment Lists DPOs ****************************/
3418 format_sr_segment_list_dpo (u8 * s, va_list * args)
3420 ip6_sr_main_t *sm = &sr_main;
3421 ip6_address_t *addr;
3424 index_t index = va_arg (*args, index_t);
3425 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3426 s = format (s, "SR: Segment List index:[%d]", index);
3427 s = format (s, "\n\tSegments:");
3429 sl = pool_elt_at_index (sm->sid_lists, index);
3431 s = format (s, "< ");
3432 vec_foreach (addr, sl->segments)
3434 s = format (s, "%U, ", format_ip6_address, addr);
3436 s = format (s, "\b\b > - ");
3437 s = format (s, "Weight: %u", sl->weight);
3442 const static dpo_vft_t sr_policy_rewrite_vft = {
3443 .dv_lock = sr_dpo_lock,
3444 .dv_unlock = sr_dpo_unlock,
3445 .dv_format = format_sr_segment_list_dpo,
3448 const static char *const sr_pr_encaps_ip6_nodes[] = {
3449 "sr-pl-rewrite-encaps",
3453 const static char *const sr_pr_encaps_ip4_nodes[] = {
3454 "sr-pl-rewrite-encaps-v4",
3458 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3459 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3460 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3463 const static char *const sr_pr_insert_ip6_nodes[] = {
3464 "sr-pl-rewrite-insert",
3468 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3469 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3472 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3473 "sr-pl-rewrite-b-insert",
3477 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3478 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3481 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3482 "sr-pl-rewrite-b-encaps",
3486 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3487 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3490 /********************* SR Policy Rewrite initialization ***********************/
3492 * @brief SR Policy Rewrite initialization
3495 sr_policy_rewrite_init (vlib_main_t * vm)
3497 ip6_sr_main_t *sm = &sr_main;
3499 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3500 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3501 sizeof (ip6_address_t));
3503 /* Init SR VPO DPOs type */
3504 sr_pr_encaps_dpo_type =
3505 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3507 sr_pr_insert_dpo_type =
3508 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3510 sr_pr_bsid_encaps_dpo_type =
3511 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3513 sr_pr_bsid_insert_dpo_type =
3514 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3516 /* Register the L2 encaps node used in HW redirect */
3517 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3519 sm->fib_table_ip6 = (u32) ~ 0;
3520 sm->fib_table_ip4 = (u32) ~ 0;
3525 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3529 * fd.io coding-style-patch-verification: ON
3532 * eval: (c-set-style "gnu")