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 appropriate 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, u8 type)
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, u8 type)
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);
361 segment_list->policy_type = sr_policy->type;
363 segment_list->egress_fib_table =
364 ip6_fib_index_from_table_id (sr_policy->fib_table);
368 segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type);
369 segment_list->rewrite_bsid = segment_list->rewrite;
373 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
374 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
377 if (sr_policy->plugin)
380 pool_elt_at_index (sm->policy_plugin_functions,
381 sr_policy->plugin - SR_BEHAVIOR_LAST);
383 segment_list->plugin = sr_policy->plugin;
384 segment_list->plugin_mem = sr_policy->plugin_mem;
386 plugin->creation (sr_policy);
390 dpo_reset (&segment_list->bsid_dpo);
391 dpo_reset (&segment_list->ip6_dpo);
392 dpo_reset (&segment_list->ip4_dpo);
396 if (!sr_policy->plugin)
398 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
399 DPO_PROTO_IP6, segment_list - sm->sid_lists);
400 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
401 DPO_PROTO_IP4, segment_list - sm->sid_lists);
402 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
403 DPO_PROTO_IP6, segment_list - sm->sid_lists);
407 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
408 segment_list - sm->sid_lists);
409 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
410 segment_list - sm->sid_lists);
411 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
412 segment_list - sm->sid_lists);
417 if (!sr_policy->plugin)
419 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
420 DPO_PROTO_IP6, segment_list - sm->sid_lists);
421 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
422 DPO_PROTO_IP6, segment_list - sm->sid_lists);
426 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
427 segment_list - sm->sid_lists);
428 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
429 segment_list - sm->sid_lists);
437 * @brief Updates the Load-Balancer after an SR Policy change
439 * @param sr_policy is the modified SR Policy
442 update_lb (ip6_sr_policy_t * sr_policy)
444 flow_hash_config_t fhc;
446 ip6_sr_sl_t *segment_list;
447 ip6_sr_main_t *sm = &sr_main;
448 load_balance_path_t path;
449 path.path_index = FIB_NODE_INDEX_INVALID;
450 load_balance_path_t *ip4_path_vector = 0;
451 load_balance_path_t *ip6_path_vector = 0;
452 load_balance_path_t *b_path_vector = 0;
454 /* In case LB does not exist, create it */
455 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
458 .fp_proto = FIB_PROTOCOL_IP6,
461 .ip6 = sr_policy->bsid,
465 /* Add FIB entry for BSID */
466 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
469 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
470 load_balance_create (0, DPO_PROTO_IP6, fhc));
472 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
473 load_balance_create (0, DPO_PROTO_IP6, fhc));
475 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
476 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
477 sr_policy->fib_table),
479 FIB_ENTRY_FLAG_EXCLUSIVE,
480 &sr_policy->bsid_dpo);
482 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
485 FIB_ENTRY_FLAG_EXCLUSIVE,
486 &sr_policy->ip6_dpo);
488 if (sr_policy->is_encap)
490 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
491 load_balance_create (0, DPO_PROTO_IP4, fhc));
493 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
496 FIB_ENTRY_FLAG_EXCLUSIVE,
497 &sr_policy->ip4_dpo);
502 /* Create the LB path vector */
503 vec_foreach (sl_index, sr_policy->segments_lists)
505 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
506 path.path_dpo = segment_list->bsid_dpo;
507 path.path_weight = segment_list->weight;
508 vec_add1 (b_path_vector, path);
509 path.path_dpo = segment_list->ip6_dpo;
510 vec_add1 (ip6_path_vector, path);
511 if (sr_policy->is_encap)
513 path.path_dpo = segment_list->ip4_dpo;
514 vec_add1 (ip4_path_vector, path);
518 /* Update LB multipath */
519 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
520 LOAD_BALANCE_FLAG_NONE);
521 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
522 LOAD_BALANCE_FLAG_NONE);
523 if (sr_policy->is_encap)
524 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
525 LOAD_BALANCE_FLAG_NONE);
528 vec_free (b_path_vector);
529 vec_free (ip6_path_vector);
530 vec_free (ip4_path_vector);
534 * @brief Updates the Replicate DPO after an SR Policy change
536 * @param sr_policy is the modified SR Policy (type spray)
539 update_replicate (ip6_sr_policy_t * sr_policy)
542 ip6_sr_sl_t *segment_list;
543 ip6_sr_main_t *sm = &sr_main;
544 load_balance_path_t path;
545 path.path_index = FIB_NODE_INDEX_INVALID;
546 load_balance_path_t *b_path_vector = 0;
547 load_balance_path_t *ip6_path_vector = 0;
548 load_balance_path_t *ip4_path_vector = 0;
550 /* In case LB does not exist, create it */
551 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
553 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
554 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
556 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
557 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
559 /* Update FIB entry's DPO to point to SR without LB */
561 .fp_proto = FIB_PROTOCOL_IP6,
564 .ip6 = sr_policy->bsid,
567 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
568 sr_policy->fib_table),
570 FIB_ENTRY_FLAG_EXCLUSIVE,
571 &sr_policy->bsid_dpo);
573 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
576 FIB_ENTRY_FLAG_EXCLUSIVE,
577 &sr_policy->ip6_dpo);
579 if (sr_policy->is_encap)
581 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
582 replicate_create (0, DPO_PROTO_IP4));
584 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
587 FIB_ENTRY_FLAG_EXCLUSIVE,
588 &sr_policy->ip4_dpo);
593 /* Create the replicate path vector */
594 path.path_weight = 1;
595 vec_foreach (sl_index, sr_policy->segments_lists)
597 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
598 path.path_dpo = segment_list->bsid_dpo;
599 vec_add1 (b_path_vector, path);
600 path.path_dpo = segment_list->ip6_dpo;
601 vec_add1 (ip6_path_vector, path);
602 if (sr_policy->is_encap)
604 path.path_dpo = segment_list->ip4_dpo;
605 vec_add1 (ip4_path_vector, path);
609 /* Update replicate multipath */
610 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
611 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
612 if (sr_policy->is_encap)
613 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
616 /******************************* SR rewrite API *******************************/
617 /* Three functions for handling sr policies:
621 * All of them are API. CLI function on sr_policy_command_fn */
624 * @brief Create a new SR policy
626 * @param bsid is the bindingSID of the SR Policy
627 * @param segments is a vector of IPv6 address composing the segment list
628 * @param weight is the weight of the sid list. optional.
629 * @param behavior is the behavior of the SR policy. (default//spray)
630 * @param fib_table is the VRF where to install the FIB entry for the BSID
631 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
633 * @return 0 if correct, else error
636 sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight,
637 u8 type, u32 fib_table, u8 is_encap, u16 plugin,
640 ip6_sr_main_t *sm = &sr_main;
641 ip6_sr_policy_t *sr_policy = 0;
644 /* Search for existing keys (BSID) */
645 p = mhash_get (&sm->sr_policies_index_hash, bsid);
648 /* Add SR policy that already exists; complain */
652 /* Search collision in FIB entries */
653 /* Explanation: It might be possible that some other entity has already
654 * created a route for the BSID. This in theory is impossible, but in
655 * practise we could see it. Assert it and scream if needed */
657 .fp_proto = FIB_PROTOCOL_IP6,
664 /* Lookup the FIB index associated to the table selected */
665 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
666 (fib_table != (u32) ~ 0 ? fib_table : 0));
670 /* Lookup whether there exists an entry for the BSID */
671 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
672 if (FIB_NODE_INDEX_INVALID != fei)
673 return -12; //There is an entry for such lookup
675 /* Add an SR policy object */
676 pool_get (sm->sr_policies, sr_policy);
677 clib_memset (sr_policy, 0, sizeof (*sr_policy));
678 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
679 sr_policy->type = type;
680 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
681 sr_policy->is_encap = is_encap;
685 sr_policy->plugin = plugin;
686 sr_policy->plugin_mem = ls_plugin_mem;
690 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
693 /* Create a segment list and add the index to the SR policy */
694 create_sl (sr_policy, segments, weight, is_encap);
696 /* If FIB doesnt exist, create them */
697 if (sm->fib_table_ip6 == (u32) ~ 0)
699 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
701 "SRv6 steering of IP6 prefixes through BSIDs");
702 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
704 "SRv6 steering of IP4 prefixes through BSIDs");
707 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
708 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
709 update_lb (sr_policy);
710 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
711 update_replicate (sr_policy);
716 * @brief Delete a SR policy
718 * @param bsid is the bindingSID of the SR Policy
719 * @param index is the index of the SR policy
721 * @return 0 if correct, else error
724 sr_policy_del (ip6_address_t * bsid, u32 index)
726 ip6_sr_main_t *sm = &sr_main;
727 ip6_sr_policy_t *sr_policy = 0;
728 ip6_sr_sl_t *segment_list;
734 p = mhash_get (&sm->sr_policies_index_hash, bsid);
736 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
742 sr_policy = pool_elt_at_index (sm->sr_policies, index);
745 /* Remove BindingSID FIB entry */
747 .fp_proto = FIB_PROTOCOL_IP6,
750 .ip6 = sr_policy->bsid,
755 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
756 sr_policy->fib_table),
757 &pfx, FIB_SOURCE_SR);
759 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
761 if (sr_policy->is_encap)
762 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
764 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
766 dpo_reset (&sr_policy->bsid_dpo);
767 dpo_reset (&sr_policy->ip4_dpo);
768 dpo_reset (&sr_policy->ip6_dpo);
771 /* Clean SID Lists */
772 vec_foreach (sl_index, sr_policy->segments_lists)
774 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
775 vec_free (segment_list->segments);
776 vec_free (segment_list->rewrite);
777 if (!sr_policy->is_encap)
778 vec_free (segment_list->rewrite_bsid);
779 pool_put_index (sm->sid_lists, *sl_index);
782 if (sr_policy->plugin)
784 sr_policy_fn_registration_t *plugin = 0;
787 pool_elt_at_index (sm->policy_plugin_functions,
788 sr_policy->plugin - SR_BEHAVIOR_LAST);
790 plugin->removal (sr_policy);
791 sr_policy->plugin = 0;
792 sr_policy->plugin_mem = NULL;
795 /* Remove SR policy entry */
796 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
797 pool_put (sm->sr_policies, sr_policy);
799 /* If FIB empty unlock it */
800 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
802 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
803 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
804 sm->fib_table_ip6 = (u32) ~ 0;
805 sm->fib_table_ip4 = (u32) ~ 0;
812 * @brief Modify an existing SR policy
814 * The possible modifications are adding a new Segment List, modifying an
815 * existing Segment List (modify the weight only) and delete a given
816 * Segment List from the SR Policy.
818 * @param bsid is the bindingSID of the SR Policy
819 * @param index is the index of the SR policy
820 * @param fib_table is the VRF where to install the FIB entry for the BSID
821 * @param operation is the operation to perform (among the top ones)
822 * @param segments is a vector of IPv6 address composing the segment list
823 * @param sl_index is the index of the Segment List to modify/delete
824 * @param weight is the weight of the sid list. optional.
825 * @param is_encap Mode. Encapsulation or SRH insertion.
827 * @return 0 if correct, else error
830 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
831 u8 operation, ip6_address_t * segments, u32 sl_index,
834 ip6_sr_main_t *sm = &sr_main;
835 ip6_sr_policy_t *sr_policy = 0;
836 ip6_sr_sl_t *segment_list;
837 u32 *sl_index_iterate;
842 p = mhash_get (&sm->sr_policies_index_hash, bsid);
844 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
850 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;
936 u8 type = SR_POLICY_TYPE_DEFAULT;
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"))
975 type = SR_POLICY_TYPE_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, type, fib_table, is_encap,
1025 behavior, ls_plugin_mem);
1027 vec_free (segments);
1030 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1035 return clib_error_return (0, "No SL modification specified");
1036 if (operation != 1 && sl_index == (u32) ~ 0)
1037 return clib_error_return (0, "No Segment List index specified");
1038 if (operation == 1 && vec_len (segments) == 0)
1039 return clib_error_return (0, "No Segment List specified");
1040 if (operation == 3 && weight == (u32) ~ 0)
1041 return clib_error_return (0, "No new weight for the SL specified");
1043 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1044 sr_policy_index, fib_table, operation, segments,
1048 vec_free (segments);
1058 return clib_error_return (0,
1059 "There is already a FIB entry for the BindingSID address.\n"
1060 "The SR policy could not be created.");
1062 return clib_error_return (0, "The specified FIB table does not exist.");
1064 return clib_error_return (0,
1065 "The selected SR policy only contains ONE segment list. "
1066 "Please remove the SR policy instead");
1068 return clib_error_return (0,
1069 "Could not delete the segment list. "
1070 "It is not associated with that SR policy.");
1072 return clib_error_return (0,
1073 "Could not modify the segment list. "
1074 "The given SL is not associated with such SR policy.");
1076 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1082 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1083 .path = "sr policy",
1084 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1085 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1087 "Manipulation of SR policies.\n"
1088 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1089 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1090 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1091 "Each SR policy will be associated with a unique BindingSID.\n"
1092 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1093 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1094 "The add command will create a SR policy with its first segment list (sl)\n"
1095 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1096 "within an SR policy.\n"
1097 "The del command allows you to delete a SR policy along with all its associated\n"
1099 .function = sr_policy_command_fn,
1104 * @brief CLI to display onscreen all the SR policies
1106 static clib_error_t *
1107 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1108 vlib_cli_command_t * cmd)
1110 ip6_sr_main_t *sm = &sr_main;
1112 ip6_sr_sl_t *segment_list = 0;
1113 ip6_sr_policy_t *sr_policy = 0;
1114 ip6_sr_policy_t **vec_policies = 0;
1115 ip6_address_t *addr;
1119 vlib_cli_output (vm, "SR policies:");
1122 pool_foreach (sr_policy, sm->sr_policies)
1123 {vec_add1 (vec_policies, sr_policy); }
1126 vec_foreach_index (i, vec_policies)
1128 sr_policy = vec_policies[i];
1129 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1130 (u32) (sr_policy - sm->sr_policies),
1131 format_ip6_address, &sr_policy->bsid);
1132 vlib_cli_output (vm, "\tBehavior: %s",
1133 (sr_policy->is_encap ? "Encapsulation" :
1135 switch (sr_policy->type)
1137 case SR_POLICY_TYPE_SPRAY:
1138 vlib_cli_output (vm, "\tType: %s", "Spray");
1141 vlib_cli_output (vm, "\tType: %s", "Default");
1144 vlib_cli_output (vm, "\tFIB table: %u",
1145 (sr_policy->fib_table !=
1146 (u32) ~ 0 ? sr_policy->fib_table : 0));
1147 vlib_cli_output (vm, "\tSegment Lists:");
1148 vec_foreach (sl_index, sr_policy->segments_lists)
1151 s = format (s, "\t[%u].- ", *sl_index);
1152 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1153 s = format (s, "< ");
1154 vec_foreach (addr, segment_list->segments)
1156 s = format (s, "%U, ", format_ip6_address, addr);
1158 s = format (s, "\b\b > ");
1159 s = format (s, "weight: %u", segment_list->weight);
1160 vlib_cli_output (vm, " %v", s);
1162 vlib_cli_output (vm, "-----------");
1168 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1169 .path = "show sr policies",
1170 .short_help = "show sr policies",
1171 .function = show_sr_policies_command_fn,
1176 * @brief CLI to display onscreen the SR encaps source addr
1178 static clib_error_t *
1179 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1180 vlib_cli_command_t * cmd)
1182 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1183 sr_get_encaps_source ());
1189 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1190 .path = "show sr encaps source addr",
1191 .short_help = "show sr encaps source addr",
1192 .function = show_sr_encaps_source_command_fn,
1197 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1199 static clib_error_t *
1200 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1201 unformat_input_t * input,
1202 vlib_cli_command_t * cmd)
1204 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1210 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1211 .path = "show sr encaps hop-limit",
1212 .short_help = "show sr encaps hop-limit",
1213 .function = show_sr_encaps_hop_limit_command_fn,
1217 /*************************** SR rewrite graph node ****************************/
1219 * @brief Trace for the SR Policy Rewrite graph node
1222 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1225 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1226 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1227 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1230 (s, "SR-policy-rewrite: src %U dst %U",
1231 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1237 * @brief IPv6 encapsulation processing as per RFC2473
1239 static_always_inline void
1240 encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1241 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1247 ip0_encap->hop_limit -= 1;
1249 ip0->payload_length + sizeof (ip6_header_t) +
1250 clib_net_to_host_u16 (ip0_encap->payload_length);
1251 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1253 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1254 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1256 (clib_net_to_host_u32 (
1257 ip0_encap->ip_version_traffic_class_and_flow_label) &
1259 (flow_label & 0x0000ffff));
1263 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1266 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1267 vlib_frame_t * from_frame)
1269 ip6_sr_main_t *sm = &sr_main;
1270 u32 n_left_from, next_index, *from, *to_next;
1272 from = vlib_frame_vector_args (from_frame);
1273 n_left_from = from_frame->n_vectors;
1275 next_index = node->cached_next_index;
1277 int encap_pkts = 0, bsid_pkts = 0;
1279 while (n_left_from > 0)
1283 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1286 while (n_left_from >= 8 && n_left_to_next >= 4)
1288 u32 bi0, bi1, bi2, bi3;
1289 vlib_buffer_t *b0, *b1, *b2, *b3;
1290 u32 next0, next1, next2, next3;
1291 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1292 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1293 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1294 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1296 /* Prefetch next iteration. */
1298 vlib_buffer_t *p4, *p5, *p6, *p7;
1300 p4 = vlib_get_buffer (vm, from[4]);
1301 p5 = vlib_get_buffer (vm, from[5]);
1302 p6 = vlib_get_buffer (vm, from[6]);
1303 p7 = vlib_get_buffer (vm, from[7]);
1305 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1306 vlib_prefetch_buffer_header (p4, LOAD);
1307 vlib_prefetch_buffer_header (p5, LOAD);
1308 vlib_prefetch_buffer_header (p6, LOAD);
1309 vlib_prefetch_buffer_header (p7, LOAD);
1311 clib_prefetch_store (p4->data);
1312 clib_prefetch_store (p5->data);
1313 clib_prefetch_store (p6->data);
1314 clib_prefetch_store (p7->data);
1317 to_next[0] = bi0 = from[0];
1318 to_next[1] = bi1 = from[1];
1319 to_next[2] = bi2 = from[2];
1320 to_next[3] = bi3 = from[3];
1324 n_left_to_next -= 4;
1326 b0 = vlib_get_buffer (vm, bi0);
1327 b1 = vlib_get_buffer (vm, bi1);
1328 b2 = vlib_get_buffer (vm, bi2);
1329 b3 = vlib_get_buffer (vm, bi3);
1332 pool_elt_at_index (sm->sid_lists,
1333 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1335 pool_elt_at_index (sm->sid_lists,
1336 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1338 pool_elt_at_index (sm->sid_lists,
1339 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1341 pool_elt_at_index (sm->sid_lists,
1342 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1344 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1345 vec_len (sl0->rewrite));
1346 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1347 vec_len (sl1->rewrite));
1348 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1349 vec_len (sl2->rewrite));
1350 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1351 vec_len (sl3->rewrite));
1353 ip0_encap = vlib_buffer_get_current (b0);
1354 ip1_encap = vlib_buffer_get_current (b1);
1355 ip2_encap = vlib_buffer_get_current (b2);
1356 ip3_encap = vlib_buffer_get_current (b3);
1358 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1359 sl0->rewrite, vec_len (sl0->rewrite));
1360 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1361 sl1->rewrite, vec_len (sl1->rewrite));
1362 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1363 sl2->rewrite, vec_len (sl2->rewrite));
1364 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1365 sl3->rewrite, vec_len (sl3->rewrite));
1367 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1368 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1369 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1370 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1372 ip0 = vlib_buffer_get_current (b0);
1373 ip1 = vlib_buffer_get_current (b1);
1374 ip2 = vlib_buffer_get_current (b2);
1375 ip3 = vlib_buffer_get_current (b3);
1377 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1378 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1379 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1380 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
1382 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1383 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1384 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1385 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1387 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1389 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1391 sr_policy_rewrite_trace_t *tr =
1392 vlib_add_trace (vm, node, b0, sizeof (*tr));
1393 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1394 sizeof (tr->src.as_u8));
1395 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1396 sizeof (tr->dst.as_u8));
1399 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1401 sr_policy_rewrite_trace_t *tr =
1402 vlib_add_trace (vm, node, b1, sizeof (*tr));
1403 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1404 sizeof (tr->src.as_u8));
1405 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1406 sizeof (tr->dst.as_u8));
1409 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1411 sr_policy_rewrite_trace_t *tr =
1412 vlib_add_trace (vm, node, b2, sizeof (*tr));
1413 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1414 sizeof (tr->src.as_u8));
1415 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1416 sizeof (tr->dst.as_u8));
1419 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1421 sr_policy_rewrite_trace_t *tr =
1422 vlib_add_trace (vm, node, b3, sizeof (*tr));
1423 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1424 sizeof (tr->src.as_u8));
1425 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1426 sizeof (tr->dst.as_u8));
1431 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1432 n_left_to_next, bi0, bi1, bi2, bi3,
1433 next0, next1, next2, next3);
1436 /* Single loop for potentially the last three packets */
1437 while (n_left_from > 0 && n_left_to_next > 0)
1441 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1443 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1450 n_left_to_next -= 1;
1451 b0 = vlib_get_buffer (vm, bi0);
1454 pool_elt_at_index (sm->sid_lists,
1455 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1456 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1457 vec_len (sl0->rewrite));
1459 ip0_encap = vlib_buffer_get_current (b0);
1461 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1462 sl0->rewrite, vec_len (sl0->rewrite));
1463 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1465 ip0 = vlib_buffer_get_current (b0);
1467 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1469 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1471 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1472 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b0, sizeof (*tr));
1476 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
1483 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1484 n_left_to_next, bi0, next0);
1487 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1490 /* Update counters */
1491 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1492 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1494 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1495 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1498 return from_frame->n_vectors;
1502 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1503 .function = sr_policy_rewrite_encaps,
1504 .name = "sr-pl-rewrite-encaps",
1505 .vector_size = sizeof (u32),
1506 .format_trace = format_sr_policy_rewrite_trace,
1507 .type = VLIB_NODE_TYPE_INTERNAL,
1508 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1509 .error_strings = sr_policy_rewrite_error_strings,
1510 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1512 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1513 foreach_sr_policy_rewrite_next
1520 * @brief IPv4 encapsulation processing as per RFC2473
1522 static_always_inline void
1523 encaps_processing_v4 (vlib_node_runtime_t * node,
1525 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1528 ip6_sr_header_t *sr0;
1533 /* Inner IPv4: Decrement TTL & update checksum */
1534 ip0_encap->ttl -= 1;
1535 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1536 checksum0 += checksum0 >= 0xffff;
1537 ip0_encap->checksum = checksum0;
1539 /* Outer IPv6: Update length, FL, proto */
1540 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1541 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1542 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1543 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1544 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1545 (flow_label & 0x0000ffff));
1546 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1548 sr0 = (void *) (ip0 + 1);
1549 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1552 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1556 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1559 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1560 vlib_frame_t * from_frame)
1562 ip6_sr_main_t *sm = &sr_main;
1563 u32 n_left_from, next_index, *from, *to_next;
1565 from = vlib_frame_vector_args (from_frame);
1566 n_left_from = from_frame->n_vectors;
1568 next_index = node->cached_next_index;
1570 int encap_pkts = 0, bsid_pkts = 0;
1572 while (n_left_from > 0)
1576 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1579 while (n_left_from >= 8 && n_left_to_next >= 4)
1581 u32 bi0, bi1, bi2, bi3;
1582 vlib_buffer_t *b0, *b1, *b2, *b3;
1583 u32 next0, next1, next2, next3;
1584 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1585 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1586 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1587 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1589 /* Prefetch next iteration. */
1591 vlib_buffer_t *p4, *p5, *p6, *p7;
1593 p4 = vlib_get_buffer (vm, from[4]);
1594 p5 = vlib_get_buffer (vm, from[5]);
1595 p6 = vlib_get_buffer (vm, from[6]);
1596 p7 = vlib_get_buffer (vm, from[7]);
1598 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1599 vlib_prefetch_buffer_header (p4, LOAD);
1600 vlib_prefetch_buffer_header (p5, LOAD);
1601 vlib_prefetch_buffer_header (p6, LOAD);
1602 vlib_prefetch_buffer_header (p7, LOAD);
1604 clib_prefetch_store (p4->data);
1605 clib_prefetch_store (p5->data);
1606 clib_prefetch_store (p6->data);
1607 clib_prefetch_store (p7->data);
1610 to_next[0] = bi0 = from[0];
1611 to_next[1] = bi1 = from[1];
1612 to_next[2] = bi2 = from[2];
1613 to_next[3] = bi3 = from[3];
1617 n_left_to_next -= 4;
1619 b0 = vlib_get_buffer (vm, bi0);
1620 b1 = vlib_get_buffer (vm, bi1);
1621 b2 = vlib_get_buffer (vm, bi2);
1622 b3 = vlib_get_buffer (vm, bi3);
1625 pool_elt_at_index (sm->sid_lists,
1626 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1628 pool_elt_at_index (sm->sid_lists,
1629 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1631 pool_elt_at_index (sm->sid_lists,
1632 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1634 pool_elt_at_index (sm->sid_lists,
1635 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1636 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1637 vec_len (sl0->rewrite));
1638 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1639 vec_len (sl1->rewrite));
1640 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1641 vec_len (sl2->rewrite));
1642 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1643 vec_len (sl3->rewrite));
1645 ip0_encap = vlib_buffer_get_current (b0);
1646 ip1_encap = vlib_buffer_get_current (b1);
1647 ip2_encap = vlib_buffer_get_current (b2);
1648 ip3_encap = vlib_buffer_get_current (b3);
1650 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1651 sl0->rewrite, vec_len (sl0->rewrite));
1652 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1653 sl1->rewrite, vec_len (sl1->rewrite));
1654 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1655 sl2->rewrite, vec_len (sl2->rewrite));
1656 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1657 sl3->rewrite, vec_len (sl3->rewrite));
1659 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1660 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1661 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1662 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1664 ip0 = vlib_buffer_get_current (b0);
1665 ip1 = vlib_buffer_get_current (b1);
1666 ip2 = vlib_buffer_get_current (b2);
1667 ip3 = vlib_buffer_get_current (b3);
1669 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1670 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1671 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1672 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1674 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1675 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1676 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1677 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1679 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1681 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1683 sr_policy_rewrite_trace_t *tr =
1684 vlib_add_trace (vm, node, b0, sizeof (*tr));
1685 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1686 sizeof (tr->src.as_u8));
1687 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1688 sizeof (tr->dst.as_u8));
1691 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1693 sr_policy_rewrite_trace_t *tr =
1694 vlib_add_trace (vm, node, b1, sizeof (*tr));
1695 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1696 sizeof (tr->src.as_u8));
1697 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1698 sizeof (tr->dst.as_u8));
1701 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1703 sr_policy_rewrite_trace_t *tr =
1704 vlib_add_trace (vm, node, b2, sizeof (*tr));
1705 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1706 sizeof (tr->src.as_u8));
1707 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1708 sizeof (tr->dst.as_u8));
1711 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1713 sr_policy_rewrite_trace_t *tr =
1714 vlib_add_trace (vm, node, b3, sizeof (*tr));
1715 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1716 sizeof (tr->src.as_u8));
1717 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1718 sizeof (tr->dst.as_u8));
1723 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1724 n_left_to_next, bi0, bi1, bi2, bi3,
1725 next0, next1, next2, next3);
1728 /* Single loop for potentially the last three packets */
1729 while (n_left_from > 0 && n_left_to_next > 0)
1733 ip6_header_t *ip0 = 0;
1734 ip4_header_t *ip0_encap = 0;
1736 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1743 n_left_to_next -= 1;
1744 b0 = vlib_get_buffer (vm, bi0);
1747 pool_elt_at_index (sm->sid_lists,
1748 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1749 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1750 vec_len (sl0->rewrite));
1752 ip0_encap = vlib_buffer_get_current (b0);
1754 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1755 sl0->rewrite, vec_len (sl0->rewrite));
1756 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1758 ip0 = vlib_buffer_get_current (b0);
1760 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1762 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1764 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1765 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1767 sr_policy_rewrite_trace_t *tr =
1768 vlib_add_trace (vm, node, b0, sizeof (*tr));
1769 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1770 sizeof (tr->src.as_u8));
1771 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1772 sizeof (tr->dst.as_u8));
1776 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1777 n_left_to_next, bi0, next0);
1780 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1783 /* Update counters */
1784 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1785 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1787 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1788 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1791 return from_frame->n_vectors;
1795 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1796 .function = sr_policy_rewrite_encaps_v4,
1797 .name = "sr-pl-rewrite-encaps-v4",
1798 .vector_size = sizeof (u32),
1799 .format_trace = format_sr_policy_rewrite_trace,
1800 .type = VLIB_NODE_TYPE_INTERNAL,
1801 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1802 .error_strings = sr_policy_rewrite_error_strings,
1803 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1805 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1806 foreach_sr_policy_rewrite_next
1813 ip_flow_hash (void *data)
1815 ip4_header_t *iph = (ip4_header_t *) data;
1817 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1818 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1820 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1826 return (*((u64 *) m) & 0xffffffffffff);
1830 l2_flow_hash (vlib_buffer_t * b0)
1832 ethernet_header_t *eh;
1834 uword is_ip, eh_size;
1837 eh = vlib_buffer_get_current (b0);
1838 eh_type = clib_net_to_host_u16 (eh->type);
1839 eh_size = ethernet_buffer_header_size (b0);
1841 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1843 /* since we have 2 cache lines, use them */
1845 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1849 b = mac_to_u64 ((u8 *) eh->dst_address);
1850 c = mac_to_u64 ((u8 *) eh->src_address);
1851 hash_mix64 (a, b, c);
1857 * @brief Graph node for applying a SR policy into a L2 frame
1860 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1861 vlib_frame_t * from_frame)
1863 ip6_sr_main_t *sm = &sr_main;
1864 u32 n_left_from, next_index, *from, *to_next;
1866 from = vlib_frame_vector_args (from_frame);
1867 n_left_from = from_frame->n_vectors;
1869 next_index = node->cached_next_index;
1871 int encap_pkts = 0, bsid_pkts = 0;
1873 while (n_left_from > 0)
1877 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1880 while (n_left_from >= 8 && n_left_to_next >= 4)
1882 u32 bi0, bi1, bi2, bi3;
1883 vlib_buffer_t *b0, *b1, *b2, *b3;
1884 u32 next0, next1, next2, next3;
1885 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1886 ethernet_header_t *en0, *en1, *en2, *en3;
1887 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1888 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1889 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1890 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1891 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1893 /* Prefetch next iteration. */
1895 vlib_buffer_t *p4, *p5, *p6, *p7;
1897 p4 = vlib_get_buffer (vm, from[4]);
1898 p5 = vlib_get_buffer (vm, from[5]);
1899 p6 = vlib_get_buffer (vm, from[6]);
1900 p7 = vlib_get_buffer (vm, from[7]);
1902 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1903 vlib_prefetch_buffer_header (p4, LOAD);
1904 vlib_prefetch_buffer_header (p5, LOAD);
1905 vlib_prefetch_buffer_header (p6, LOAD);
1906 vlib_prefetch_buffer_header (p7, LOAD);
1908 clib_prefetch_store (p4->data);
1909 clib_prefetch_store (p5->data);
1910 clib_prefetch_store (p6->data);
1911 clib_prefetch_store (p7->data);
1914 to_next[0] = bi0 = from[0];
1915 to_next[1] = bi1 = from[1];
1916 to_next[2] = bi2 = from[2];
1917 to_next[3] = bi3 = from[3];
1921 n_left_to_next -= 4;
1923 b0 = vlib_get_buffer (vm, bi0);
1924 b1 = vlib_get_buffer (vm, bi1);
1925 b2 = vlib_get_buffer (vm, bi2);
1926 b3 = vlib_get_buffer (vm, bi3);
1928 sp0 = pool_elt_at_index (sm->sr_policies,
1929 sm->sw_iface_sr_policies[vnet_buffer
1933 sp1 = pool_elt_at_index (sm->sr_policies,
1934 sm->sw_iface_sr_policies[vnet_buffer
1938 sp2 = pool_elt_at_index (sm->sr_policies,
1939 sm->sw_iface_sr_policies[vnet_buffer
1943 sp3 = pool_elt_at_index (sm->sr_policies,
1944 sm->sw_iface_sr_policies[vnet_buffer
1947 flow_label0 = l2_flow_hash (b0);
1948 flow_label1 = l2_flow_hash (b1);
1949 flow_label2 = l2_flow_hash (b2);
1950 flow_label3 = l2_flow_hash (b3);
1952 if (vec_len (sp0->segments_lists) == 1)
1953 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1956 vnet_buffer (b0)->ip.flow_hash = flow_label0;
1957 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1958 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1959 (vec_len (sp0->segments_lists) - 1))];
1962 if (vec_len (sp1->segments_lists) == 1)
1963 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1966 vnet_buffer (b1)->ip.flow_hash = flow_label1;
1967 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1968 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1969 (vec_len (sp1->segments_lists) - 1))];
1972 if (vec_len (sp2->segments_lists) == 1)
1973 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1976 vnet_buffer (b2)->ip.flow_hash = flow_label2;
1977 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1978 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1979 (vec_len (sp2->segments_lists) - 1))];
1982 if (vec_len (sp3->segments_lists) == 1)
1983 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1986 vnet_buffer (b3)->ip.flow_hash = flow_label3;
1987 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1988 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1989 (vec_len (sp3->segments_lists) - 1))];
1993 pool_elt_at_index (sm->sid_lists,
1994 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1996 pool_elt_at_index (sm->sid_lists,
1997 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1999 pool_elt_at_index (sm->sid_lists,
2000 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2002 pool_elt_at_index (sm->sid_lists,
2003 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2005 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2006 vec_len (sl0->rewrite));
2007 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2008 vec_len (sl1->rewrite));
2009 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2010 vec_len (sl2->rewrite));
2011 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2012 vec_len (sl3->rewrite));
2014 en0 = vlib_buffer_get_current (b0);
2015 en1 = vlib_buffer_get_current (b1);
2016 en2 = vlib_buffer_get_current (b2);
2017 en3 = vlib_buffer_get_current (b3);
2019 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2020 sl0->rewrite, vec_len (sl0->rewrite));
2021 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2022 sl1->rewrite, vec_len (sl1->rewrite));
2023 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2024 sl2->rewrite, vec_len (sl2->rewrite));
2025 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2026 sl3->rewrite, vec_len (sl3->rewrite));
2028 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2029 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2030 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2031 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2033 ip0 = vlib_buffer_get_current (b0);
2034 ip1 = vlib_buffer_get_current (b1);
2035 ip2 = vlib_buffer_get_current (b2);
2036 ip3 = vlib_buffer_get_current (b3);
2038 ip0->payload_length =
2039 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2040 ip1->payload_length =
2041 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2042 ip2->payload_length =
2043 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2044 ip3->payload_length =
2045 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2047 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2049 sr0 = (void *) (ip0 + 1);
2050 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2053 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2055 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2057 sr1 = (void *) (ip1 + 1);
2058 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2061 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2063 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2065 sr2 = (void *) (ip2 + 1);
2066 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2069 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2071 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2073 sr3 = (void *) (ip3 + 1);
2074 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2077 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2079 /* TC is set to 0 for all ethernet frames, should be taken from COS
2080 * od DSCP of encapsulated packet in the future */
2081 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2082 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2083 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2084 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2085 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2086 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2087 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2088 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2090 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2092 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2094 sr_policy_rewrite_trace_t *tr =
2095 vlib_add_trace (vm, node, b0, sizeof (*tr));
2096 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2097 sizeof (tr->src.as_u8));
2098 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2099 sizeof (tr->dst.as_u8));
2102 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2104 sr_policy_rewrite_trace_t *tr =
2105 vlib_add_trace (vm, node, b1, sizeof (*tr));
2106 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2107 sizeof (tr->src.as_u8));
2108 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2109 sizeof (tr->dst.as_u8));
2112 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2114 sr_policy_rewrite_trace_t *tr =
2115 vlib_add_trace (vm, node, b2, sizeof (*tr));
2116 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2117 sizeof (tr->src.as_u8));
2118 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2119 sizeof (tr->dst.as_u8));
2122 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2124 sr_policy_rewrite_trace_t *tr =
2125 vlib_add_trace (vm, node, b3, sizeof (*tr));
2126 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2127 sizeof (tr->src.as_u8));
2128 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2129 sizeof (tr->dst.as_u8));
2134 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2135 n_left_to_next, bi0, bi1, bi2, bi3,
2136 next0, next1, next2, next3);
2139 /* Single loop for potentially the last three packets */
2140 while (n_left_from > 0 && n_left_to_next > 0)
2144 ip6_header_t *ip0 = 0;
2145 ip6_sr_header_t *sr0;
2146 ethernet_header_t *en0;
2147 ip6_sr_policy_t *sp0;
2149 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2157 n_left_to_next -= 1;
2158 b0 = vlib_get_buffer (vm, bi0);
2160 /* Find the SR policy */
2161 sp0 = pool_elt_at_index (sm->sr_policies,
2162 sm->sw_iface_sr_policies[vnet_buffer
2165 flow_label0 = l2_flow_hash (b0);
2167 /* In case there is more than one SL, LB among them */
2168 if (vec_len (sp0->segments_lists) == 1)
2169 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2172 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2173 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2174 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2175 (vec_len (sp0->segments_lists) - 1))];
2178 pool_elt_at_index (sm->sid_lists,
2179 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2180 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2181 vec_len (sl0->rewrite));
2183 en0 = vlib_buffer_get_current (b0);
2185 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2186 sl0->rewrite, vec_len (sl0->rewrite));
2188 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2190 ip0 = vlib_buffer_get_current (b0);
2192 ip0->payload_length =
2193 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2195 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2197 sr0 = (void *) (ip0 + 1);
2198 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2201 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2203 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2204 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2206 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2207 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2209 sr_policy_rewrite_trace_t *tr =
2210 vlib_add_trace (vm, node, b0, sizeof (*tr));
2211 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2212 sizeof (tr->src.as_u8));
2213 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2214 sizeof (tr->dst.as_u8));
2218 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2219 n_left_to_next, bi0, next0);
2222 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2225 /* Update counters */
2226 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2227 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2229 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2230 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2233 return from_frame->n_vectors;
2237 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2238 .function = sr_policy_rewrite_encaps_l2,
2239 .name = "sr-pl-rewrite-encaps-l2",
2240 .vector_size = sizeof (u32),
2241 .format_trace = format_sr_policy_rewrite_trace,
2242 .type = VLIB_NODE_TYPE_INTERNAL,
2243 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2244 .error_strings = sr_policy_rewrite_error_strings,
2245 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2247 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2248 foreach_sr_policy_rewrite_next
2255 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2258 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2259 vlib_frame_t * from_frame)
2261 ip6_sr_main_t *sm = &sr_main;
2262 u32 n_left_from, next_index, *from, *to_next;
2264 from = vlib_frame_vector_args (from_frame);
2265 n_left_from = from_frame->n_vectors;
2267 next_index = node->cached_next_index;
2269 int insert_pkts = 0, bsid_pkts = 0;
2271 while (n_left_from > 0)
2275 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2278 while (n_left_from >= 8 && n_left_to_next >= 4)
2280 u32 bi0, bi1, bi2, bi3;
2281 vlib_buffer_t *b0, *b1, *b2, *b3;
2282 u32 next0, next1, next2, next3;
2283 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2284 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2285 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2286 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2287 u16 new_l0, new_l1, new_l2, new_l3;
2289 /* Prefetch next iteration. */
2291 vlib_buffer_t *p4, *p5, *p6, *p7;
2293 p4 = vlib_get_buffer (vm, from[4]);
2294 p5 = vlib_get_buffer (vm, from[5]);
2295 p6 = vlib_get_buffer (vm, from[6]);
2296 p7 = vlib_get_buffer (vm, from[7]);
2298 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2299 vlib_prefetch_buffer_header (p4, LOAD);
2300 vlib_prefetch_buffer_header (p5, LOAD);
2301 vlib_prefetch_buffer_header (p6, LOAD);
2302 vlib_prefetch_buffer_header (p7, LOAD);
2304 clib_prefetch_store (p4->data);
2305 clib_prefetch_store (p5->data);
2306 clib_prefetch_store (p6->data);
2307 clib_prefetch_store (p7->data);
2310 to_next[0] = bi0 = from[0];
2311 to_next[1] = bi1 = from[1];
2312 to_next[2] = bi2 = from[2];
2313 to_next[3] = bi3 = from[3];
2317 n_left_to_next -= 4;
2319 b0 = vlib_get_buffer (vm, bi0);
2320 b1 = vlib_get_buffer (vm, bi1);
2321 b2 = vlib_get_buffer (vm, bi2);
2322 b3 = vlib_get_buffer (vm, bi3);
2325 pool_elt_at_index (sm->sid_lists,
2326 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2328 pool_elt_at_index (sm->sid_lists,
2329 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2331 pool_elt_at_index (sm->sid_lists,
2332 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2334 pool_elt_at_index (sm->sid_lists,
2335 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2336 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2337 vec_len (sl0->rewrite));
2338 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2339 vec_len (sl1->rewrite));
2340 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2341 vec_len (sl2->rewrite));
2342 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2343 vec_len (sl3->rewrite));
2345 ip0 = vlib_buffer_get_current (b0);
2346 ip1 = vlib_buffer_get_current (b1);
2347 ip2 = vlib_buffer_get_current (b2);
2348 ip3 = vlib_buffer_get_current (b3);
2350 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2352 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2353 ip6_ext_header_len (ip0 + 1));
2355 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2357 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2359 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2360 ip6_ext_header_len (ip1 + 1));
2362 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2364 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2366 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2367 ip6_ext_header_len (ip2 + 1));
2369 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2371 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2373 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2374 ip6_ext_header_len (ip3 + 1));
2376 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2378 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2379 (void *) sr0 - (void *) ip0);
2380 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2381 (void *) sr1 - (void *) ip1);
2382 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2383 (void *) sr2 - (void *) ip2);
2384 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2385 (void *) sr3 - (void *) ip3);
2387 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2388 sl0->rewrite, vec_len (sl0->rewrite));
2389 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2390 sl1->rewrite, vec_len (sl1->rewrite));
2391 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2392 sl2->rewrite, vec_len (sl2->rewrite));
2393 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2394 sl3->rewrite, vec_len (sl3->rewrite));
2396 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2397 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2398 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2399 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2401 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2402 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2403 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2404 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2406 ip0->hop_limit -= 1;
2407 ip1->hop_limit -= 1;
2408 ip2->hop_limit -= 1;
2409 ip3->hop_limit -= 1;
2412 clib_net_to_host_u16 (ip0->payload_length) +
2413 vec_len (sl0->rewrite);
2415 clib_net_to_host_u16 (ip1->payload_length) +
2416 vec_len (sl1->rewrite);
2418 clib_net_to_host_u16 (ip2->payload_length) +
2419 vec_len (sl2->rewrite);
2421 clib_net_to_host_u16 (ip3->payload_length) +
2422 vec_len (sl3->rewrite);
2424 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2425 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2426 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2427 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2429 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2430 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2431 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2432 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2434 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2435 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2436 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2437 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2438 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2439 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2440 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2441 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2443 ip0->dst_address.as_u64[0] =
2444 (sr0->segments + sr0->segments_left)->as_u64[0];
2445 ip0->dst_address.as_u64[1] =
2446 (sr0->segments + sr0->segments_left)->as_u64[1];
2447 ip1->dst_address.as_u64[0] =
2448 (sr1->segments + sr1->segments_left)->as_u64[0];
2449 ip1->dst_address.as_u64[1] =
2450 (sr1->segments + sr1->segments_left)->as_u64[1];
2451 ip2->dst_address.as_u64[0] =
2452 (sr2->segments + sr2->segments_left)->as_u64[0];
2453 ip2->dst_address.as_u64[1] =
2454 (sr2->segments + sr2->segments_left)->as_u64[1];
2455 ip3->dst_address.as_u64[0] =
2456 (sr3->segments + sr3->segments_left)->as_u64[0];
2457 ip3->dst_address.as_u64[1] =
2458 (sr3->segments + sr3->segments_left)->as_u64[1];
2460 ip6_ext_header_t *ip_ext;
2461 if (ip0 + 1 == (void *) sr0)
2463 sr0->protocol = ip0->protocol;
2464 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2468 ip_ext = (void *) (ip0 + 1);
2469 sr0->protocol = ip_ext->next_hdr;
2470 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2473 if (ip1 + 1 == (void *) sr1)
2475 sr1->protocol = ip1->protocol;
2476 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2480 ip_ext = (void *) (ip2 + 1);
2481 sr2->protocol = ip_ext->next_hdr;
2482 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2485 if (ip2 + 1 == (void *) sr2)
2487 sr2->protocol = ip2->protocol;
2488 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2492 ip_ext = (void *) (ip2 + 1);
2493 sr2->protocol = ip_ext->next_hdr;
2494 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2497 if (ip3 + 1 == (void *) sr3)
2499 sr3->protocol = ip3->protocol;
2500 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2504 ip_ext = (void *) (ip3 + 1);
2505 sr3->protocol = ip_ext->next_hdr;
2506 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2511 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2513 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2515 sr_policy_rewrite_trace_t *tr =
2516 vlib_add_trace (vm, node, b0, sizeof (*tr));
2517 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2518 sizeof (tr->src.as_u8));
2519 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2520 sizeof (tr->dst.as_u8));
2523 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2525 sr_policy_rewrite_trace_t *tr =
2526 vlib_add_trace (vm, node, b1, sizeof (*tr));
2527 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2528 sizeof (tr->src.as_u8));
2529 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2530 sizeof (tr->dst.as_u8));
2533 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2535 sr_policy_rewrite_trace_t *tr =
2536 vlib_add_trace (vm, node, b2, sizeof (*tr));
2537 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2538 sizeof (tr->src.as_u8));
2539 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2540 sizeof (tr->dst.as_u8));
2543 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2545 sr_policy_rewrite_trace_t *tr =
2546 vlib_add_trace (vm, node, b3, sizeof (*tr));
2547 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2548 sizeof (tr->src.as_u8));
2549 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2550 sizeof (tr->dst.as_u8));
2554 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2555 n_left_to_next, bi0, bi1, bi2, bi3,
2556 next0, next1, next2, next3);
2559 /* Single loop for potentially the last three packets */
2560 while (n_left_from > 0 && n_left_to_next > 0)
2564 ip6_header_t *ip0 = 0;
2565 ip6_sr_header_t *sr0 = 0;
2567 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2575 n_left_to_next -= 1;
2577 b0 = vlib_get_buffer (vm, bi0);
2579 pool_elt_at_index (sm->sid_lists,
2580 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2581 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2582 vec_len (sl0->rewrite));
2584 ip0 = vlib_buffer_get_current (b0);
2586 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2588 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2589 ip6_ext_header_len (ip0 + 1));
2591 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2593 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2594 (void *) sr0 - (void *) ip0);
2595 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2596 sl0->rewrite, vec_len (sl0->rewrite));
2598 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2600 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2601 ip0->hop_limit -= 1;
2603 clib_net_to_host_u16 (ip0->payload_length) +
2604 vec_len (sl0->rewrite);
2605 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2607 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2608 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2609 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2611 ip0->dst_address.as_u64[0] =
2612 (sr0->segments + sr0->segments_left)->as_u64[0];
2613 ip0->dst_address.as_u64[1] =
2614 (sr0->segments + sr0->segments_left)->as_u64[1];
2616 if (ip0 + 1 == (void *) sr0)
2618 sr0->protocol = ip0->protocol;
2619 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2623 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2624 sr0->protocol = ip_ext->next_hdr;
2625 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2628 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2629 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2631 sr_policy_rewrite_trace_t *tr =
2632 vlib_add_trace (vm, node, b0, sizeof (*tr));
2633 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2634 sizeof (tr->src.as_u8));
2635 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2636 sizeof (tr->dst.as_u8));
2641 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2642 n_left_to_next, bi0, next0);
2645 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2648 /* Update counters */
2649 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2650 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2652 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2653 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2655 return from_frame->n_vectors;
2659 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2660 .function = sr_policy_rewrite_insert,
2661 .name = "sr-pl-rewrite-insert",
2662 .vector_size = sizeof (u32),
2663 .format_trace = format_sr_policy_rewrite_trace,
2664 .type = VLIB_NODE_TYPE_INTERNAL,
2665 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2666 .error_strings = sr_policy_rewrite_error_strings,
2667 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2669 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2670 foreach_sr_policy_rewrite_next
2677 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2680 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2681 vlib_frame_t * from_frame)
2683 ip6_sr_main_t *sm = &sr_main;
2684 u32 n_left_from, next_index, *from, *to_next;
2686 from = vlib_frame_vector_args (from_frame);
2687 n_left_from = from_frame->n_vectors;
2689 next_index = node->cached_next_index;
2691 int insert_pkts = 0, bsid_pkts = 0;
2693 while (n_left_from > 0)
2697 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2700 while (n_left_from >= 8 && n_left_to_next >= 4)
2702 u32 bi0, bi1, bi2, bi3;
2703 vlib_buffer_t *b0, *b1, *b2, *b3;
2704 u32 next0, next1, next2, next3;
2705 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2706 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2707 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2708 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2709 u16 new_l0, new_l1, new_l2, new_l3;
2711 /* Prefetch next iteration. */
2713 vlib_buffer_t *p4, *p5, *p6, *p7;
2715 p4 = vlib_get_buffer (vm, from[4]);
2716 p5 = vlib_get_buffer (vm, from[5]);
2717 p6 = vlib_get_buffer (vm, from[6]);
2718 p7 = vlib_get_buffer (vm, from[7]);
2720 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2721 vlib_prefetch_buffer_header (p4, LOAD);
2722 vlib_prefetch_buffer_header (p5, LOAD);
2723 vlib_prefetch_buffer_header (p6, LOAD);
2724 vlib_prefetch_buffer_header (p7, LOAD);
2726 clib_prefetch_store (p4->data);
2727 clib_prefetch_store (p5->data);
2728 clib_prefetch_store (p6->data);
2729 clib_prefetch_store (p7->data);
2732 to_next[0] = bi0 = from[0];
2733 to_next[1] = bi1 = from[1];
2734 to_next[2] = bi2 = from[2];
2735 to_next[3] = bi3 = from[3];
2739 n_left_to_next -= 4;
2741 b0 = vlib_get_buffer (vm, bi0);
2742 b1 = vlib_get_buffer (vm, bi1);
2743 b2 = vlib_get_buffer (vm, bi2);
2744 b3 = vlib_get_buffer (vm, bi3);
2747 pool_elt_at_index (sm->sid_lists,
2748 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2750 pool_elt_at_index (sm->sid_lists,
2751 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2753 pool_elt_at_index (sm->sid_lists,
2754 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2756 pool_elt_at_index (sm->sid_lists,
2757 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2758 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2759 vec_len (sl0->rewrite_bsid));
2760 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2761 vec_len (sl1->rewrite_bsid));
2762 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2763 vec_len (sl2->rewrite_bsid));
2764 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2765 vec_len (sl3->rewrite_bsid));
2767 ip0 = vlib_buffer_get_current (b0);
2768 ip1 = vlib_buffer_get_current (b1);
2769 ip2 = vlib_buffer_get_current (b2);
2770 ip3 = vlib_buffer_get_current (b3);
2772 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2774 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2775 ip6_ext_header_len (ip0 + 1));
2777 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2779 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2781 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2782 ip6_ext_header_len (ip1 + 1));
2784 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2786 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2788 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2789 ip6_ext_header_len (ip2 + 1));
2791 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2793 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2795 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2796 ip6_ext_header_len (ip3 + 1));
2798 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2800 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2801 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2802 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2803 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2804 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2805 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2806 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2807 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2809 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2810 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2811 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2812 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2813 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2814 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2815 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2816 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2818 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2819 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2820 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2821 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2823 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2824 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2825 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2826 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2828 ip0->hop_limit -= 1;
2829 ip1->hop_limit -= 1;
2830 ip2->hop_limit -= 1;
2831 ip3->hop_limit -= 1;
2834 clib_net_to_host_u16 (ip0->payload_length) +
2835 vec_len (sl0->rewrite_bsid);
2837 clib_net_to_host_u16 (ip1->payload_length) +
2838 vec_len (sl1->rewrite_bsid);
2840 clib_net_to_host_u16 (ip2->payload_length) +
2841 vec_len (sl2->rewrite_bsid);
2843 clib_net_to_host_u16 (ip3->payload_length) +
2844 vec_len (sl3->rewrite_bsid);
2846 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2847 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2848 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2849 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2851 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2852 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2853 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2854 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2856 ip0->dst_address.as_u64[0] =
2857 (sr0->segments + sr0->segments_left)->as_u64[0];
2858 ip0->dst_address.as_u64[1] =
2859 (sr0->segments + sr0->segments_left)->as_u64[1];
2860 ip1->dst_address.as_u64[0] =
2861 (sr1->segments + sr1->segments_left)->as_u64[0];
2862 ip1->dst_address.as_u64[1] =
2863 (sr1->segments + sr1->segments_left)->as_u64[1];
2864 ip2->dst_address.as_u64[0] =
2865 (sr2->segments + sr2->segments_left)->as_u64[0];
2866 ip2->dst_address.as_u64[1] =
2867 (sr2->segments + sr2->segments_left)->as_u64[1];
2868 ip3->dst_address.as_u64[0] =
2869 (sr3->segments + sr3->segments_left)->as_u64[0];
2870 ip3->dst_address.as_u64[1] =
2871 (sr3->segments + sr3->segments_left)->as_u64[1];
2873 ip6_ext_header_t *ip_ext;
2874 if (ip0 + 1 == (void *) sr0)
2876 sr0->protocol = ip0->protocol;
2877 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2881 ip_ext = (void *) (ip0 + 1);
2882 sr0->protocol = ip_ext->next_hdr;
2883 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2886 if (ip1 + 1 == (void *) sr1)
2888 sr1->protocol = ip1->protocol;
2889 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2893 ip_ext = (void *) (ip2 + 1);
2894 sr2->protocol = ip_ext->next_hdr;
2895 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2898 if (ip2 + 1 == (void *) sr2)
2900 sr2->protocol = ip2->protocol;
2901 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2905 ip_ext = (void *) (ip2 + 1);
2906 sr2->protocol = ip_ext->next_hdr;
2907 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2910 if (ip3 + 1 == (void *) sr3)
2912 sr3->protocol = ip3->protocol;
2913 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2917 ip_ext = (void *) (ip3 + 1);
2918 sr3->protocol = ip_ext->next_hdr;
2919 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2924 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2926 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2928 sr_policy_rewrite_trace_t *tr =
2929 vlib_add_trace (vm, node, b0, sizeof (*tr));
2930 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2931 sizeof (tr->src.as_u8));
2932 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2933 sizeof (tr->dst.as_u8));
2936 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2938 sr_policy_rewrite_trace_t *tr =
2939 vlib_add_trace (vm, node, b1, sizeof (*tr));
2940 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2941 sizeof (tr->src.as_u8));
2942 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2943 sizeof (tr->dst.as_u8));
2946 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2948 sr_policy_rewrite_trace_t *tr =
2949 vlib_add_trace (vm, node, b2, sizeof (*tr));
2950 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2951 sizeof (tr->src.as_u8));
2952 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2953 sizeof (tr->dst.as_u8));
2956 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2958 sr_policy_rewrite_trace_t *tr =
2959 vlib_add_trace (vm, node, b3, sizeof (*tr));
2960 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2961 sizeof (tr->src.as_u8));
2962 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2963 sizeof (tr->dst.as_u8));
2967 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2968 n_left_to_next, bi0, bi1, bi2, bi3,
2969 next0, next1, next2, next3);
2972 /* Single loop for potentially the last three packets */
2973 while (n_left_from > 0 && n_left_to_next > 0)
2977 ip6_header_t *ip0 = 0;
2978 ip6_sr_header_t *sr0 = 0;
2980 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2988 n_left_to_next -= 1;
2990 b0 = vlib_get_buffer (vm, bi0);
2992 pool_elt_at_index (sm->sid_lists,
2993 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2994 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2995 vec_len (sl0->rewrite_bsid));
2997 ip0 = vlib_buffer_get_current (b0);
2999 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3001 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3002 ip6_ext_header_len (ip0 + 1));
3004 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3006 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3007 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3008 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3009 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3011 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3013 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3014 ip0->hop_limit -= 1;
3016 clib_net_to_host_u16 (ip0->payload_length) +
3017 vec_len (sl0->rewrite_bsid);
3018 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3020 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3022 ip0->dst_address.as_u64[0] =
3023 (sr0->segments + sr0->segments_left)->as_u64[0];
3024 ip0->dst_address.as_u64[1] =
3025 (sr0->segments + sr0->segments_left)->as_u64[1];
3027 if (ip0 + 1 == (void *) sr0)
3029 sr0->protocol = ip0->protocol;
3030 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3034 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3035 sr0->protocol = ip_ext->next_hdr;
3036 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3039 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3040 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3042 sr_policy_rewrite_trace_t *tr =
3043 vlib_add_trace (vm, node, b0, sizeof (*tr));
3044 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3045 sizeof (tr->src.as_u8));
3046 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3047 sizeof (tr->dst.as_u8));
3052 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3053 n_left_to_next, bi0, next0);
3056 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3059 /* Update counters */
3060 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3061 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3063 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3064 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3066 return from_frame->n_vectors;
3070 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3071 .function = sr_policy_rewrite_b_insert,
3072 .name = "sr-pl-rewrite-b-insert",
3073 .vector_size = sizeof (u32),
3074 .format_trace = format_sr_policy_rewrite_trace,
3075 .type = VLIB_NODE_TYPE_INTERNAL,
3076 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3077 .error_strings = sr_policy_rewrite_error_strings,
3078 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3080 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3081 foreach_sr_policy_rewrite_next
3088 * @brief Function BSID encapsulation
3090 static_always_inline void
3091 end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3092 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3093 u32 *next0, u8 policy_type)
3095 ip6_address_t *new_dst0;
3097 if (PREDICT_FALSE (!sr0))
3098 goto error_bsid_encaps;
3100 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3102 if (PREDICT_TRUE (sr0->segments_left != 0))
3104 sr0->segments_left -= 1;
3105 new_dst0 = (ip6_address_t *) (sr0->segments);
3106 new_dst0 += sr0->segments_left;
3107 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3108 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3114 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3115 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3119 * @brief Graph node for applying a SR policy BSID - Encapsulation
3122 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3123 vlib_frame_t * from_frame)
3125 ip6_sr_main_t *sm = &sr_main;
3126 u32 n_left_from, next_index, *from, *to_next;
3128 from = vlib_frame_vector_args (from_frame);
3129 n_left_from = from_frame->n_vectors;
3131 next_index = node->cached_next_index;
3133 int encap_pkts = 0, bsid_pkts = 0;
3135 while (n_left_from > 0)
3139 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3142 while (n_left_from >= 8 && n_left_to_next >= 4)
3144 u32 bi0, bi1, bi2, bi3;
3145 vlib_buffer_t *b0, *b1, *b2, *b3;
3146 u32 next0, next1, next2, next3;
3147 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3148 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3149 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3150 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3151 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3153 /* Prefetch next iteration. */
3155 vlib_buffer_t *p4, *p5, *p6, *p7;
3157 p4 = vlib_get_buffer (vm, from[4]);
3158 p5 = vlib_get_buffer (vm, from[5]);
3159 p6 = vlib_get_buffer (vm, from[6]);
3160 p7 = vlib_get_buffer (vm, from[7]);
3162 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3163 vlib_prefetch_buffer_header (p4, LOAD);
3164 vlib_prefetch_buffer_header (p5, LOAD);
3165 vlib_prefetch_buffer_header (p6, LOAD);
3166 vlib_prefetch_buffer_header (p7, LOAD);
3168 clib_prefetch_store (p4->data);
3169 clib_prefetch_store (p5->data);
3170 clib_prefetch_store (p6->data);
3171 clib_prefetch_store (p7->data);
3174 to_next[0] = bi0 = from[0];
3175 to_next[1] = bi1 = from[1];
3176 to_next[2] = bi2 = from[2];
3177 to_next[3] = bi3 = from[3];
3181 n_left_to_next -= 4;
3183 b0 = vlib_get_buffer (vm, bi0);
3184 b1 = vlib_get_buffer (vm, bi1);
3185 b2 = vlib_get_buffer (vm, bi2);
3186 b3 = vlib_get_buffer (vm, bi3);
3189 pool_elt_at_index (sm->sid_lists,
3190 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3192 pool_elt_at_index (sm->sid_lists,
3193 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3195 pool_elt_at_index (sm->sid_lists,
3196 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3198 pool_elt_at_index (sm->sid_lists,
3199 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3200 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3201 vec_len (sl0->rewrite));
3202 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3203 vec_len (sl1->rewrite));
3204 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3205 vec_len (sl2->rewrite));
3206 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3207 vec_len (sl3->rewrite));
3209 ip0_encap = vlib_buffer_get_current (b0);
3210 ip1_encap = vlib_buffer_get_current (b1);
3211 ip2_encap = vlib_buffer_get_current (b2);
3212 ip3_encap = vlib_buffer_get_current (b3);
3215 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3218 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3221 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3224 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3227 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3229 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3231 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3233 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3236 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3237 sl0->rewrite, vec_len (sl0->rewrite));
3238 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3239 sl1->rewrite, vec_len (sl1->rewrite));
3240 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3241 sl2->rewrite, vec_len (sl2->rewrite));
3242 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3243 sl3->rewrite, vec_len (sl3->rewrite));
3245 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3246 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3247 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3248 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3250 ip0 = vlib_buffer_get_current (b0);
3251 ip1 = vlib_buffer_get_current (b1);
3252 ip2 = vlib_buffer_get_current (b2);
3253 ip3 = vlib_buffer_get_current (b3);
3255 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3256 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3257 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3258 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
3260 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3262 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3264 sr_policy_rewrite_trace_t *tr =
3265 vlib_add_trace (vm, node, b0, sizeof (*tr));
3266 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3267 sizeof (tr->src.as_u8));
3268 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3269 sizeof (tr->dst.as_u8));
3272 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3274 sr_policy_rewrite_trace_t *tr =
3275 vlib_add_trace (vm, node, b1, sizeof (*tr));
3276 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3277 sizeof (tr->src.as_u8));
3278 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3279 sizeof (tr->dst.as_u8));
3282 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3284 sr_policy_rewrite_trace_t *tr =
3285 vlib_add_trace (vm, node, b2, sizeof (*tr));
3286 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3287 sizeof (tr->src.as_u8));
3288 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3289 sizeof (tr->dst.as_u8));
3292 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3294 sr_policy_rewrite_trace_t *tr =
3295 vlib_add_trace (vm, node, b3, sizeof (*tr));
3296 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3297 sizeof (tr->src.as_u8));
3298 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3299 sizeof (tr->dst.as_u8));
3304 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3305 n_left_to_next, bi0, bi1, bi2, bi3,
3306 next0, next1, next2, next3);
3309 /* Single loop for potentially the last three packets */
3310 while (n_left_from > 0 && n_left_to_next > 0)
3314 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3315 ip6_sr_header_t *sr0;
3317 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3324 n_left_to_next -= 1;
3325 b0 = vlib_get_buffer (vm, bi0);
3328 pool_elt_at_index (sm->sid_lists,
3329 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3330 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3331 vec_len (sl0->rewrite));
3333 ip0_encap = vlib_buffer_get_current (b0);
3335 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3337 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3340 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3341 sl0->rewrite, vec_len (sl0->rewrite));
3342 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3344 ip0 = vlib_buffer_get_current (b0);
3346 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3348 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3349 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3351 sr_policy_rewrite_trace_t *tr =
3352 vlib_add_trace (vm, node, b0, sizeof (*tr));
3353 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3354 sizeof (tr->src.as_u8));
3355 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3356 sizeof (tr->dst.as_u8));
3360 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3361 n_left_to_next, bi0, next0);
3364 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3367 /* Update counters */
3368 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3369 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3371 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3372 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3375 return from_frame->n_vectors;
3379 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3380 .function = sr_policy_rewrite_b_encaps,
3381 .name = "sr-pl-rewrite-b-encaps",
3382 .vector_size = sizeof (u32),
3383 .format_trace = format_sr_policy_rewrite_trace,
3384 .type = VLIB_NODE_TYPE_INTERNAL,
3385 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3386 .error_strings = sr_policy_rewrite_error_strings,
3387 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3389 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3390 foreach_sr_policy_rewrite_next
3396 /*************************** SR Policy plugins ******************************/
3398 * @brief SR Policy plugin registry
3401 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3402 u8 * keyword_str, u8 * def_str,
3403 u8 * params_str, u8 prefix_length,
3405 format_function_t * ls_format,
3406 unformat_function_t * ls_unformat,
3407 sr_p_plugin_callback_t * creation_fn,
3408 sr_p_plugin_callback_t * removal_fn)
3410 ip6_sr_main_t *sm = &sr_main;
3413 sr_policy_fn_registration_t *plugin;
3415 /* Did this function exist? If so update it */
3416 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3419 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3421 /* Else create a new one and set hash key */
3424 pool_get (sm->policy_plugin_functions, plugin);
3425 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3426 plugin - sm->policy_plugin_functions);
3429 clib_memset (plugin, 0, sizeof (*plugin));
3431 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3432 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3433 plugin->prefix_length = prefix_length;
3434 plugin->ls_format = ls_format;
3435 plugin->ls_unformat = ls_unformat;
3436 plugin->creation = creation_fn;
3437 plugin->removal = removal_fn;
3438 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3439 plugin->function_name = format (0, "%s%c", fn_name, 0);
3440 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3441 plugin->def_str = format (0, "%s%c", def_str, 0);
3442 plugin->params_str = format (0, "%s%c", params_str, 0);
3444 return plugin->sr_policy_function_number;
3448 * @brief CLI function to 'show' all available SR LocalSID behaviors
3450 static clib_error_t *
3451 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3452 unformat_input_t * input,
3453 vlib_cli_command_t * cmd)
3455 ip6_sr_main_t *sm = &sr_main;
3456 sr_policy_fn_registration_t *plugin;
3457 sr_policy_fn_registration_t **plugins_vec = 0;
3460 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3463 pool_foreach (plugin, sm->policy_plugin_functions)
3464 { vec_add1 (plugins_vec, plugin); }
3467 vlib_cli_output (vm, "Plugin behaviors:\n");
3468 for (i = 0; i < vec_len (plugins_vec); i++)
3470 plugin = plugins_vec[i];
3471 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3473 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3479 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3480 .path = "show sr policy behaviors",
3481 .short_help = "show sr policy behaviors",
3482 .function = show_sr_policy_behaviors_command_fn,
3486 /*************************** SR Segment Lists DPOs ****************************/
3488 format_sr_segment_list_dpo (u8 * s, va_list * args)
3490 ip6_sr_main_t *sm = &sr_main;
3491 ip6_address_t *addr;
3494 index_t index = va_arg (*args, index_t);
3495 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3496 s = format (s, "SR: Segment List index:[%d]", index);
3497 s = format (s, "\n\tSegments:");
3499 sl = pool_elt_at_index (sm->sid_lists, index);
3501 s = format (s, "< ");
3502 vec_foreach (addr, sl->segments)
3504 s = format (s, "%U, ", format_ip6_address, addr);
3506 s = format (s, "\b\b > - ");
3507 s = format (s, "Weight: %u", sl->weight);
3512 const static dpo_vft_t sr_policy_rewrite_vft = {
3513 .dv_lock = sr_dpo_lock,
3514 .dv_unlock = sr_dpo_unlock,
3515 .dv_format = format_sr_segment_list_dpo,
3518 const static char *const sr_pr_encaps_ip6_nodes[] = {
3519 "sr-pl-rewrite-encaps",
3523 const static char *const sr_pr_encaps_ip4_nodes[] = {
3524 "sr-pl-rewrite-encaps-v4",
3528 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3529 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3530 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3533 const static char *const sr_pr_insert_ip6_nodes[] = {
3534 "sr-pl-rewrite-insert",
3538 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3539 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3542 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3543 "sr-pl-rewrite-b-insert",
3547 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3548 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3551 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3552 "sr-pl-rewrite-b-encaps",
3556 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3557 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3560 /********************* SR Policy Rewrite initialization ***********************/
3562 * @brief SR Policy Rewrite initialization
3565 sr_policy_rewrite_init (vlib_main_t * vm)
3567 ip6_sr_main_t *sm = &sr_main;
3569 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3570 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3571 sizeof (ip6_address_t));
3573 /* Init SR VPO DPOs type */
3574 sr_pr_encaps_dpo_type =
3575 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3577 sr_pr_insert_dpo_type =
3578 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3580 sr_pr_bsid_encaps_dpo_type =
3581 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3583 sr_pr_bsid_insert_dpo_type =
3584 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3586 /* Register the L2 encaps node used in HW redirect */
3587 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3589 sm->fib_table_ip6 = (u32) ~ 0;
3590 sm->fib_table_ip4 = (u32) ~ 0;
3595 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3599 * fd.io coding-style-patch-verification: ON
3602 * eval: (c-set-style "gnu")