2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip4_inlines.h>
45 #include <vnet/ip/ip6_inlines.h>
46 #include <vnet/srv6/sr_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
110 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
112 /******************* SR rewrite set encaps IPv6 source addr *******************/
113 /* Note: This is temporal. We don't know whether to follow this path or
114 take the ip address of a loopback interface or even the OIF */
117 sr_set_source (ip6_address_t * address)
119 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
123 sr_get_encaps_source ()
125 return &sr_pr_encaps_src;
128 static clib_error_t *
129 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130 vlib_cli_command_t * cmd)
132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
135 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
138 return clib_error_return (0, "No address specified");
140 return clib_error_return (0, "No address specified");
144 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145 .path = "set sr encaps source",
146 .short_help = "set sr encaps source addr <ip6_addr>",
147 .function = set_sr_src_command_fn,
151 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
154 sr_set_hop_limit (u8 hop_limit)
156 sr_pr_encaps_hop_limit = hop_limit;
160 sr_get_hop_limit (void)
162 return sr_pr_encaps_hop_limit;
165 static clib_error_t *
166 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167 vlib_cli_command_t * cmd)
169 int hop_limit = sr_get_hop_limit ();
171 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172 return clib_error_return (0, "No value specified");
173 if (!unformat (input, "%d", &hop_limit))
174 return clib_error_return (0, "Invalid value");
175 if (hop_limit <= 0 || hop_limit > 255)
176 return clib_error_return (0, "Value out of range [1-255]");
177 sr_pr_encaps_hop_limit = (u8) hop_limit;
182 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183 .path = "set sr encaps hop-limit",
184 .short_help = "set sr encaps hop-limit <value>",
185 .function = set_sr_hop_limit_command_fn,
189 /*********************** SR rewrite string computation ************************/
191 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
193 * @param sl is a vector of IPv6 addresses composing the Segment List
195 * @return precomputed rewrite string for encapsulation
198 compute_rewrite_encaps (ip6_address_t *sl, 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);
747 /* Remove BindingSID FIB entry */
749 .fp_proto = FIB_PROTOCOL_IP6,
752 .ip6 = sr_policy->bsid,
757 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
758 sr_policy->fib_table),
759 &pfx, FIB_SOURCE_SR);
761 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
763 if (sr_policy->is_encap)
764 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
766 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
768 dpo_reset (&sr_policy->bsid_dpo);
769 dpo_reset (&sr_policy->ip4_dpo);
770 dpo_reset (&sr_policy->ip6_dpo);
773 /* Clean SID Lists */
774 vec_foreach (sl_index, sr_policy->segments_lists)
776 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
777 vec_free (segment_list->segments);
778 vec_free (segment_list->rewrite);
779 if (!sr_policy->is_encap)
780 vec_free (segment_list->rewrite_bsid);
781 pool_put_index (sm->sid_lists, *sl_index);
784 if (sr_policy->plugin)
786 sr_policy_fn_registration_t *plugin = 0;
789 pool_elt_at_index (sm->policy_plugin_functions,
790 sr_policy->plugin - SR_BEHAVIOR_LAST);
792 plugin->removal (sr_policy);
793 sr_policy->plugin = 0;
794 sr_policy->plugin_mem = NULL;
797 /* Remove SR policy entry */
798 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
799 pool_put (sm->sr_policies, sr_policy);
801 /* If FIB empty unlock it */
802 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
804 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
805 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
806 sm->fib_table_ip6 = (u32) ~ 0;
807 sm->fib_table_ip4 = (u32) ~ 0;
814 * @brief Modify an existing SR policy
816 * The possible modifications are adding a new Segment List, modifying an
817 * existing Segment List (modify the weight only) and delete a given
818 * Segment List from the SR Policy.
820 * @param bsid is the bindingSID of the SR Policy
821 * @param index is the index of the SR policy
822 * @param fib_table is the VRF where to install the FIB entry for the BSID
823 * @param operation is the operation to perform (among the top ones)
824 * @param segments is a vector of IPv6 address composing the segment list
825 * @param sl_index is the index of the Segment List to modify/delete
826 * @param weight is the weight of the sid list. optional.
827 * @param is_encap Mode. Encapsulation or SRH insertion.
829 * @return 0 if correct, else error
832 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
833 u8 operation, ip6_address_t * segments, u32 sl_index,
836 ip6_sr_main_t *sm = &sr_main;
837 ip6_sr_policy_t *sr_policy = 0;
838 ip6_sr_sl_t *segment_list;
839 u32 *sl_index_iterate;
844 p = mhash_get (&sm->sr_policies_index_hash, bsid);
846 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
852 sr_policy = pool_elt_at_index (sm->sr_policies, index);
857 if (operation == 1) /* Add SR List to an existing SR policy */
859 /* Create the new SL */
861 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
863 /* Create a new LB DPO */
864 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
865 update_lb (sr_policy);
866 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
867 update_replicate (sr_policy);
869 else if (operation == 2) /* Delete SR List from an existing SR policy */
871 /* Check that currently there are more than one SID list */
872 if (vec_len (sr_policy->segments_lists) == 1)
875 /* Check that the SR list does exist and is assigned to the sr policy */
876 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
877 if (*sl_index_iterate == sl_index)
880 if (*sl_index_iterate != sl_index)
883 /* Remove the lucky SR list that is being kicked out */
884 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
885 vec_free (segment_list->segments);
886 vec_free (segment_list->rewrite);
887 if (!sr_policy->is_encap)
888 vec_free (segment_list->rewrite_bsid);
889 pool_put_index (sm->sid_lists, sl_index);
890 vec_del1 (sr_policy->segments_lists,
891 sl_index_iterate - sr_policy->segments_lists);
893 /* Create a new LB DPO */
894 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
895 update_lb (sr_policy);
896 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
897 update_replicate (sr_policy);
899 else if (operation == 3) /* Modify the weight of an existing SR List */
901 /* Find the corresponding SL */
902 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
903 if (*sl_index_iterate == sl_index)
906 if (*sl_index_iterate != sl_index)
909 /* Change the weight */
910 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
911 segment_list->weight = weight;
914 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
915 update_lb (sr_policy);
917 else /* Incorrect op. */
924 * @brief CLI for 'sr policies' command family
926 static clib_error_t *
927 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
928 vlib_cli_command_t * cmd)
930 ip6_sr_main_t *sm = &sr_main;
932 char is_del = 0, is_add = 0, is_mod = 0;
934 ip6_address_t bsid, next_address;
935 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
936 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
937 ip6_address_t *segments = 0, *this_seg;
940 u8 type = SR_POLICY_TYPE_DEFAULT;
942 void *ls_plugin_mem = 0;
944 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
946 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
948 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
950 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
953 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
955 else if (!is_add && !policy_set
956 && unformat (input, "index %d", &sr_policy_index))
958 else if (unformat (input, "weight %d", &weight));
960 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
962 vec_add2 (segments, this_seg, 1);
963 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
966 else if (unformat (input, "add sl"))
968 else if (unformat (input, "del sl index %d", &sl_index))
970 else if (unformat (input, "mod sl index %d", &sl_index))
972 else if (fib_table == (u32) ~ 0
973 && unformat (input, "fib-table %d", &fib_table));
974 else if (unformat (input, "encap"))
976 else if (unformat (input, "insert"))
978 else if (unformat (input, "spray"))
979 type = SR_POLICY_TYPE_SPRAY;
980 else if (!behavior && unformat (input, "behavior"))
982 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
983 sr_policy_fn_registration_t **plugin_it = 0;
986 pool_foreach (plugin, sm->policy_plugin_functions)
988 vec_add1 (vec_plugins, plugin);
992 vec_foreach (plugin_it, vec_plugins)
995 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
997 behavior = (*plugin_it)->sr_policy_function_number;
1004 return clib_error_return (0, "Invalid behavior");
1011 if (!is_add && !is_mod && !is_del)
1012 return clib_error_return (0, "Incorrect CLI");
1015 return clib_error_return (0, "No SR policy BSID or index specified");
1019 if (behavior && vec_len (segments) == 0)
1021 vec_add2 (segments, this_seg, 1);
1022 clib_memset (this_seg, 0, sizeof (*this_seg));
1025 if (vec_len (segments) == 0)
1026 return clib_error_return (0, "No Segment List specified");
1028 rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap,
1029 behavior, ls_plugin_mem);
1031 vec_free (segments);
1034 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1039 return clib_error_return (0, "No SL modification specified");
1040 if (operation != 1 && sl_index == (u32) ~ 0)
1041 return clib_error_return (0, "No Segment List index specified");
1042 if (operation == 1 && vec_len (segments) == 0)
1043 return clib_error_return (0, "No Segment List specified");
1044 if (operation == 3 && weight == (u32) ~ 0)
1045 return clib_error_return (0, "No new weight for the SL specified");
1047 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1048 sr_policy_index, fib_table, operation, segments,
1052 vec_free (segments);
1062 return clib_error_return (0,
1063 "There is already a FIB entry for the BindingSID address.\n"
1064 "The SR policy could not be created.");
1066 return clib_error_return (0, "The specified FIB table does not exist.");
1068 return clib_error_return (0,
1069 "The selected SR policy only contains ONE segment list. "
1070 "Please remove the SR policy instead");
1072 return clib_error_return (0,
1073 "Could not delete the segment list. "
1074 "It is not associated with that SR policy.");
1076 return clib_error_return (0,
1077 "Could not modify the segment list. "
1078 "The given SL is not associated with such SR policy.");
1080 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1086 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1087 .path = "sr policy",
1088 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1089 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1091 "Manipulation of SR policies.\n"
1092 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1093 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1094 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1095 "Each SR policy will be associated with a unique BindingSID.\n"
1096 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1097 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1098 "The add command will create a SR policy with its first segment list (sl)\n"
1099 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1100 "within an SR policy.\n"
1101 "The del command allows you to delete a SR policy along with all its associated\n"
1103 .function = sr_policy_command_fn,
1108 * @brief CLI to display onscreen all the SR policies
1110 static clib_error_t *
1111 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1112 vlib_cli_command_t * cmd)
1114 ip6_sr_main_t *sm = &sr_main;
1116 ip6_sr_sl_t *segment_list = 0;
1117 ip6_sr_policy_t *sr_policy = 0;
1118 ip6_sr_policy_t **vec_policies = 0;
1119 ip6_address_t *addr;
1123 vlib_cli_output (vm, "SR policies:");
1126 pool_foreach (sr_policy, sm->sr_policies)
1127 {vec_add1 (vec_policies, sr_policy); }
1130 vec_foreach_index (i, vec_policies)
1132 sr_policy = vec_policies[i];
1133 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1134 (u32) (sr_policy - sm->sr_policies),
1135 format_ip6_address, &sr_policy->bsid);
1136 vlib_cli_output (vm, "\tBehavior: %s",
1137 (sr_policy->is_encap ? "Encapsulation" :
1139 switch (sr_policy->type)
1141 case SR_POLICY_TYPE_SPRAY:
1142 vlib_cli_output (vm, "\tType: %s", "Spray");
1145 vlib_cli_output (vm, "\tType: %s", "Default");
1148 vlib_cli_output (vm, "\tFIB table: %u",
1149 (sr_policy->fib_table !=
1150 (u32) ~ 0 ? sr_policy->fib_table : 0));
1151 vlib_cli_output (vm, "\tSegment Lists:");
1152 vec_foreach (sl_index, sr_policy->segments_lists)
1155 s = format (s, "\t[%u].- ", *sl_index);
1156 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1157 s = format (s, "< ");
1158 vec_foreach (addr, segment_list->segments)
1160 s = format (s, "%U, ", format_ip6_address, addr);
1162 s = format (s, "\b\b > ");
1163 s = format (s, "weight: %u", segment_list->weight);
1164 vlib_cli_output (vm, " %v", s);
1166 vlib_cli_output (vm, "-----------");
1172 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1173 .path = "show sr policies",
1174 .short_help = "show sr policies",
1175 .function = show_sr_policies_command_fn,
1180 * @brief CLI to display onscreen the SR encaps source addr
1182 static clib_error_t *
1183 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1184 vlib_cli_command_t * cmd)
1186 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1187 sr_get_encaps_source ());
1193 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1194 .path = "show sr encaps source addr",
1195 .short_help = "show sr encaps source addr",
1196 .function = show_sr_encaps_source_command_fn,
1201 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1203 static clib_error_t *
1204 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1205 unformat_input_t * input,
1206 vlib_cli_command_t * cmd)
1208 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1214 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1215 .path = "show sr encaps hop-limit",
1216 .short_help = "show sr encaps hop-limit",
1217 .function = show_sr_encaps_hop_limit_command_fn,
1221 /*************************** SR rewrite graph node ****************************/
1223 * @brief Trace for the SR Policy Rewrite graph node
1226 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1229 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1230 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1231 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1234 (s, "SR-policy-rewrite: src %U dst %U",
1235 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1241 * @brief IPv6 encapsulation processing as per RFC2473
1243 static_always_inline void
1244 encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1245 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1251 ip0_encap->hop_limit -= 1;
1253 ip0->payload_length + sizeof (ip6_header_t) +
1254 clib_net_to_host_u16 (ip0_encap->payload_length);
1255 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1257 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1258 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1260 (clib_net_to_host_u32 (
1261 ip0_encap->ip_version_traffic_class_and_flow_label) &
1263 (flow_label & 0x0000ffff));
1267 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1270 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1271 vlib_frame_t * from_frame)
1273 ip6_sr_main_t *sm = &sr_main;
1274 u32 n_left_from, next_index, *from, *to_next;
1276 from = vlib_frame_vector_args (from_frame);
1277 n_left_from = from_frame->n_vectors;
1279 next_index = node->cached_next_index;
1281 int encap_pkts = 0, bsid_pkts = 0;
1283 while (n_left_from > 0)
1287 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1290 while (n_left_from >= 8 && n_left_to_next >= 4)
1292 u32 bi0, bi1, bi2, bi3;
1293 vlib_buffer_t *b0, *b1, *b2, *b3;
1294 u32 next0, next1, next2, next3;
1295 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1296 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1297 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1298 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1300 /* Prefetch next iteration. */
1302 vlib_buffer_t *p4, *p5, *p6, *p7;
1304 p4 = vlib_get_buffer (vm, from[4]);
1305 p5 = vlib_get_buffer (vm, from[5]);
1306 p6 = vlib_get_buffer (vm, from[6]);
1307 p7 = vlib_get_buffer (vm, from[7]);
1309 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1310 vlib_prefetch_buffer_header (p4, LOAD);
1311 vlib_prefetch_buffer_header (p5, LOAD);
1312 vlib_prefetch_buffer_header (p6, LOAD);
1313 vlib_prefetch_buffer_header (p7, LOAD);
1315 clib_prefetch_store (p4->data);
1316 clib_prefetch_store (p5->data);
1317 clib_prefetch_store (p6->data);
1318 clib_prefetch_store (p7->data);
1321 to_next[0] = bi0 = from[0];
1322 to_next[1] = bi1 = from[1];
1323 to_next[2] = bi2 = from[2];
1324 to_next[3] = bi3 = from[3];
1328 n_left_to_next -= 4;
1330 b0 = vlib_get_buffer (vm, bi0);
1331 b1 = vlib_get_buffer (vm, bi1);
1332 b2 = vlib_get_buffer (vm, bi2);
1333 b3 = vlib_get_buffer (vm, bi3);
1336 pool_elt_at_index (sm->sid_lists,
1337 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1339 pool_elt_at_index (sm->sid_lists,
1340 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1342 pool_elt_at_index (sm->sid_lists,
1343 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1345 pool_elt_at_index (sm->sid_lists,
1346 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1348 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1349 vec_len (sl0->rewrite));
1350 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1351 vec_len (sl1->rewrite));
1352 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1353 vec_len (sl2->rewrite));
1354 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1355 vec_len (sl3->rewrite));
1357 ip0_encap = vlib_buffer_get_current (b0);
1358 ip1_encap = vlib_buffer_get_current (b1);
1359 ip2_encap = vlib_buffer_get_current (b2);
1360 ip3_encap = vlib_buffer_get_current (b3);
1362 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1363 sl0->rewrite, vec_len (sl0->rewrite));
1364 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1365 sl1->rewrite, vec_len (sl1->rewrite));
1366 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1367 sl2->rewrite, vec_len (sl2->rewrite));
1368 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1369 sl3->rewrite, vec_len (sl3->rewrite));
1371 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1372 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1373 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1374 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1376 ip0 = vlib_buffer_get_current (b0);
1377 ip1 = vlib_buffer_get_current (b1);
1378 ip2 = vlib_buffer_get_current (b2);
1379 ip3 = vlib_buffer_get_current (b3);
1381 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1382 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1383 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1384 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
1386 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1387 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1388 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1389 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1391 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1393 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1395 sr_policy_rewrite_trace_t *tr =
1396 vlib_add_trace (vm, node, b0, sizeof (*tr));
1397 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1398 sizeof (tr->src.as_u8));
1399 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1400 sizeof (tr->dst.as_u8));
1403 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1405 sr_policy_rewrite_trace_t *tr =
1406 vlib_add_trace (vm, node, b1, sizeof (*tr));
1407 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1408 sizeof (tr->src.as_u8));
1409 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1410 sizeof (tr->dst.as_u8));
1413 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1415 sr_policy_rewrite_trace_t *tr =
1416 vlib_add_trace (vm, node, b2, sizeof (*tr));
1417 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1418 sizeof (tr->src.as_u8));
1419 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1420 sizeof (tr->dst.as_u8));
1423 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1425 sr_policy_rewrite_trace_t *tr =
1426 vlib_add_trace (vm, node, b3, sizeof (*tr));
1427 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1428 sizeof (tr->src.as_u8));
1429 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1430 sizeof (tr->dst.as_u8));
1435 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1436 n_left_to_next, bi0, bi1, bi2, bi3,
1437 next0, next1, next2, next3);
1440 /* Single loop for potentially the last three packets */
1441 while (n_left_from > 0 && n_left_to_next > 0)
1445 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1447 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1454 n_left_to_next -= 1;
1455 b0 = vlib_get_buffer (vm, bi0);
1458 pool_elt_at_index (sm->sid_lists,
1459 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1460 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1461 vec_len (sl0->rewrite));
1463 ip0_encap = vlib_buffer_get_current (b0);
1465 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1466 sl0->rewrite, vec_len (sl0->rewrite));
1467 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1469 ip0 = vlib_buffer_get_current (b0);
1471 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1473 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1475 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1476 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1478 sr_policy_rewrite_trace_t *tr =
1479 vlib_add_trace (vm, node, b0, sizeof (*tr));
1480 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1481 sizeof (tr->src.as_u8));
1482 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1483 sizeof (tr->dst.as_u8));
1487 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1488 n_left_to_next, bi0, next0);
1491 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1494 /* Update counters */
1495 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1496 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1498 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1499 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1502 return from_frame->n_vectors;
1506 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1507 .function = sr_policy_rewrite_encaps,
1508 .name = "sr-pl-rewrite-encaps",
1509 .vector_size = sizeof (u32),
1510 .format_trace = format_sr_policy_rewrite_trace,
1511 .type = VLIB_NODE_TYPE_INTERNAL,
1512 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1513 .error_strings = sr_policy_rewrite_error_strings,
1514 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1516 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1517 foreach_sr_policy_rewrite_next
1524 * @brief IPv4 encapsulation processing as per RFC2473
1526 static_always_inline void
1527 encaps_processing_v4 (vlib_node_runtime_t * node,
1529 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1532 ip6_sr_header_t *sr0;
1537 /* Inner IPv4: Decrement TTL & update checksum */
1538 ip0_encap->ttl -= 1;
1539 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1540 checksum0 += checksum0 >= 0xffff;
1541 ip0_encap->checksum = checksum0;
1543 /* Outer IPv6: Update length, FL, proto */
1544 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1545 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1546 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1547 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1548 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1549 (flow_label & 0x0000ffff));
1550 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1552 sr0 = (void *) (ip0 + 1);
1553 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1556 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1560 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1563 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1564 vlib_frame_t * from_frame)
1566 ip6_sr_main_t *sm = &sr_main;
1567 u32 n_left_from, next_index, *from, *to_next;
1569 from = vlib_frame_vector_args (from_frame);
1570 n_left_from = from_frame->n_vectors;
1572 next_index = node->cached_next_index;
1574 int encap_pkts = 0, bsid_pkts = 0;
1576 while (n_left_from > 0)
1580 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1583 while (n_left_from >= 8 && n_left_to_next >= 4)
1585 u32 bi0, bi1, bi2, bi3;
1586 vlib_buffer_t *b0, *b1, *b2, *b3;
1587 u32 next0, next1, next2, next3;
1588 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1589 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1590 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1591 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1593 /* Prefetch next iteration. */
1595 vlib_buffer_t *p4, *p5, *p6, *p7;
1597 p4 = vlib_get_buffer (vm, from[4]);
1598 p5 = vlib_get_buffer (vm, from[5]);
1599 p6 = vlib_get_buffer (vm, from[6]);
1600 p7 = vlib_get_buffer (vm, from[7]);
1602 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1603 vlib_prefetch_buffer_header (p4, LOAD);
1604 vlib_prefetch_buffer_header (p5, LOAD);
1605 vlib_prefetch_buffer_header (p6, LOAD);
1606 vlib_prefetch_buffer_header (p7, LOAD);
1608 clib_prefetch_store (p4->data);
1609 clib_prefetch_store (p5->data);
1610 clib_prefetch_store (p6->data);
1611 clib_prefetch_store (p7->data);
1614 to_next[0] = bi0 = from[0];
1615 to_next[1] = bi1 = from[1];
1616 to_next[2] = bi2 = from[2];
1617 to_next[3] = bi3 = from[3];
1621 n_left_to_next -= 4;
1623 b0 = vlib_get_buffer (vm, bi0);
1624 b1 = vlib_get_buffer (vm, bi1);
1625 b2 = vlib_get_buffer (vm, bi2);
1626 b3 = vlib_get_buffer (vm, bi3);
1629 pool_elt_at_index (sm->sid_lists,
1630 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1632 pool_elt_at_index (sm->sid_lists,
1633 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1635 pool_elt_at_index (sm->sid_lists,
1636 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1638 pool_elt_at_index (sm->sid_lists,
1639 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1640 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1641 vec_len (sl0->rewrite));
1642 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1643 vec_len (sl1->rewrite));
1644 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1645 vec_len (sl2->rewrite));
1646 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1647 vec_len (sl3->rewrite));
1649 ip0_encap = vlib_buffer_get_current (b0);
1650 ip1_encap = vlib_buffer_get_current (b1);
1651 ip2_encap = vlib_buffer_get_current (b2);
1652 ip3_encap = vlib_buffer_get_current (b3);
1654 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1655 sl0->rewrite, vec_len (sl0->rewrite));
1656 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1657 sl1->rewrite, vec_len (sl1->rewrite));
1658 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1659 sl2->rewrite, vec_len (sl2->rewrite));
1660 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1661 sl3->rewrite, vec_len (sl3->rewrite));
1663 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1664 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1665 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1666 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1668 ip0 = vlib_buffer_get_current (b0);
1669 ip1 = vlib_buffer_get_current (b1);
1670 ip2 = vlib_buffer_get_current (b2);
1671 ip3 = vlib_buffer_get_current (b3);
1673 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1674 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1675 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1676 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1678 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1679 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1680 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1681 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1683 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1685 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1687 sr_policy_rewrite_trace_t *tr =
1688 vlib_add_trace (vm, node, b0, sizeof (*tr));
1689 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1690 sizeof (tr->src.as_u8));
1691 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1692 sizeof (tr->dst.as_u8));
1695 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1697 sr_policy_rewrite_trace_t *tr =
1698 vlib_add_trace (vm, node, b1, sizeof (*tr));
1699 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1700 sizeof (tr->src.as_u8));
1701 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1702 sizeof (tr->dst.as_u8));
1705 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1707 sr_policy_rewrite_trace_t *tr =
1708 vlib_add_trace (vm, node, b2, sizeof (*tr));
1709 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1710 sizeof (tr->src.as_u8));
1711 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1712 sizeof (tr->dst.as_u8));
1715 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1717 sr_policy_rewrite_trace_t *tr =
1718 vlib_add_trace (vm, node, b3, sizeof (*tr));
1719 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1720 sizeof (tr->src.as_u8));
1721 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1722 sizeof (tr->dst.as_u8));
1727 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1728 n_left_to_next, bi0, bi1, bi2, bi3,
1729 next0, next1, next2, next3);
1732 /* Single loop for potentially the last three packets */
1733 while (n_left_from > 0 && n_left_to_next > 0)
1737 ip6_header_t *ip0 = 0;
1738 ip4_header_t *ip0_encap = 0;
1740 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1747 n_left_to_next -= 1;
1748 b0 = vlib_get_buffer (vm, bi0);
1751 pool_elt_at_index (sm->sid_lists,
1752 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1753 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1754 vec_len (sl0->rewrite));
1756 ip0_encap = vlib_buffer_get_current (b0);
1758 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1759 sl0->rewrite, vec_len (sl0->rewrite));
1760 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1762 ip0 = vlib_buffer_get_current (b0);
1764 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1766 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1768 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1769 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1771 sr_policy_rewrite_trace_t *tr =
1772 vlib_add_trace (vm, node, b0, sizeof (*tr));
1773 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1774 sizeof (tr->src.as_u8));
1775 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1776 sizeof (tr->dst.as_u8));
1780 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1781 n_left_to_next, bi0, next0);
1784 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1787 /* Update counters */
1788 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1789 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1791 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1792 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1795 return from_frame->n_vectors;
1799 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1800 .function = sr_policy_rewrite_encaps_v4,
1801 .name = "sr-pl-rewrite-encaps-v4",
1802 .vector_size = sizeof (u32),
1803 .format_trace = format_sr_policy_rewrite_trace,
1804 .type = VLIB_NODE_TYPE_INTERNAL,
1805 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1806 .error_strings = sr_policy_rewrite_error_strings,
1807 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1809 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1810 foreach_sr_policy_rewrite_next
1817 ip_flow_hash (void *data)
1819 ip4_header_t *iph = (ip4_header_t *) data;
1821 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1822 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1824 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1830 return (*((u64 *) m) & 0xffffffffffff);
1834 l2_flow_hash (vlib_buffer_t * b0)
1836 ethernet_header_t *eh;
1838 uword is_ip, eh_size;
1841 eh = vlib_buffer_get_current (b0);
1842 eh_type = clib_net_to_host_u16 (eh->type);
1843 eh_size = ethernet_buffer_header_size (b0);
1845 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1847 /* since we have 2 cache lines, use them */
1849 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1853 b = mac_to_u64 ((u8 *) eh->dst_address);
1854 c = mac_to_u64 ((u8 *) eh->src_address);
1855 hash_mix64 (a, b, c);
1861 * @brief Graph node for applying a SR policy into a L2 frame
1864 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1865 vlib_frame_t * from_frame)
1867 ip6_sr_main_t *sm = &sr_main;
1868 u32 n_left_from, next_index, *from, *to_next;
1870 from = vlib_frame_vector_args (from_frame);
1871 n_left_from = from_frame->n_vectors;
1873 next_index = node->cached_next_index;
1875 int encap_pkts = 0, bsid_pkts = 0;
1877 while (n_left_from > 0)
1881 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1884 while (n_left_from >= 8 && n_left_to_next >= 4)
1886 u32 bi0, bi1, bi2, bi3;
1887 vlib_buffer_t *b0, *b1, *b2, *b3;
1888 u32 next0, next1, next2, next3;
1889 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1890 ethernet_header_t *en0, *en1, *en2, *en3;
1891 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1892 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1893 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1894 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1895 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1897 /* Prefetch next iteration. */
1899 vlib_buffer_t *p4, *p5, *p6, *p7;
1901 p4 = vlib_get_buffer (vm, from[4]);
1902 p5 = vlib_get_buffer (vm, from[5]);
1903 p6 = vlib_get_buffer (vm, from[6]);
1904 p7 = vlib_get_buffer (vm, from[7]);
1906 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1907 vlib_prefetch_buffer_header (p4, LOAD);
1908 vlib_prefetch_buffer_header (p5, LOAD);
1909 vlib_prefetch_buffer_header (p6, LOAD);
1910 vlib_prefetch_buffer_header (p7, LOAD);
1912 clib_prefetch_store (p4->data);
1913 clib_prefetch_store (p5->data);
1914 clib_prefetch_store (p6->data);
1915 clib_prefetch_store (p7->data);
1918 to_next[0] = bi0 = from[0];
1919 to_next[1] = bi1 = from[1];
1920 to_next[2] = bi2 = from[2];
1921 to_next[3] = bi3 = from[3];
1925 n_left_to_next -= 4;
1927 b0 = vlib_get_buffer (vm, bi0);
1928 b1 = vlib_get_buffer (vm, bi1);
1929 b2 = vlib_get_buffer (vm, bi2);
1930 b3 = vlib_get_buffer (vm, bi3);
1932 sp0 = pool_elt_at_index (sm->sr_policies,
1933 sm->sw_iface_sr_policies[vnet_buffer
1937 sp1 = pool_elt_at_index (sm->sr_policies,
1938 sm->sw_iface_sr_policies[vnet_buffer
1942 sp2 = pool_elt_at_index (sm->sr_policies,
1943 sm->sw_iface_sr_policies[vnet_buffer
1947 sp3 = pool_elt_at_index (sm->sr_policies,
1948 sm->sw_iface_sr_policies[vnet_buffer
1951 flow_label0 = l2_flow_hash (b0);
1952 flow_label1 = l2_flow_hash (b1);
1953 flow_label2 = l2_flow_hash (b2);
1954 flow_label3 = l2_flow_hash (b3);
1956 if (vec_len (sp0->segments_lists) == 1)
1957 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1960 vnet_buffer (b0)->ip.flow_hash = flow_label0;
1961 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1962 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1963 (vec_len (sp0->segments_lists) - 1))];
1966 if (vec_len (sp1->segments_lists) == 1)
1967 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1970 vnet_buffer (b1)->ip.flow_hash = flow_label1;
1971 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1972 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1973 (vec_len (sp1->segments_lists) - 1))];
1976 if (vec_len (sp2->segments_lists) == 1)
1977 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1980 vnet_buffer (b2)->ip.flow_hash = flow_label2;
1981 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1982 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1983 (vec_len (sp2->segments_lists) - 1))];
1986 if (vec_len (sp3->segments_lists) == 1)
1987 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1990 vnet_buffer (b3)->ip.flow_hash = flow_label3;
1991 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1992 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1993 (vec_len (sp3->segments_lists) - 1))];
1997 pool_elt_at_index (sm->sid_lists,
1998 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2000 pool_elt_at_index (sm->sid_lists,
2001 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2003 pool_elt_at_index (sm->sid_lists,
2004 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2006 pool_elt_at_index (sm->sid_lists,
2007 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2009 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2010 vec_len (sl0->rewrite));
2011 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2012 vec_len (sl1->rewrite));
2013 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2014 vec_len (sl2->rewrite));
2015 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2016 vec_len (sl3->rewrite));
2018 en0 = vlib_buffer_get_current (b0);
2019 en1 = vlib_buffer_get_current (b1);
2020 en2 = vlib_buffer_get_current (b2);
2021 en3 = vlib_buffer_get_current (b3);
2023 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2024 sl0->rewrite, vec_len (sl0->rewrite));
2025 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2026 sl1->rewrite, vec_len (sl1->rewrite));
2027 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2028 sl2->rewrite, vec_len (sl2->rewrite));
2029 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2030 sl3->rewrite, vec_len (sl3->rewrite));
2032 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2033 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2034 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2035 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2037 ip0 = vlib_buffer_get_current (b0);
2038 ip1 = vlib_buffer_get_current (b1);
2039 ip2 = vlib_buffer_get_current (b2);
2040 ip3 = vlib_buffer_get_current (b3);
2042 ip0->payload_length =
2043 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2044 ip1->payload_length =
2045 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2046 ip2->payload_length =
2047 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2048 ip3->payload_length =
2049 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2051 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2053 sr0 = (void *) (ip0 + 1);
2054 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2057 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2059 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2061 sr1 = (void *) (ip1 + 1);
2062 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2065 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2067 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2069 sr2 = (void *) (ip2 + 1);
2070 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2073 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2075 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2077 sr3 = (void *) (ip3 + 1);
2078 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2081 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2083 /* TC is set to 0 for all ethernet frames, should be taken from COS
2084 * od DSCP of encapsulated packet in the future */
2085 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2086 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2087 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2088 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2089 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2090 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2091 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2092 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2094 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2096 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2098 sr_policy_rewrite_trace_t *tr =
2099 vlib_add_trace (vm, node, b0, sizeof (*tr));
2100 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2101 sizeof (tr->src.as_u8));
2102 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2103 sizeof (tr->dst.as_u8));
2106 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2108 sr_policy_rewrite_trace_t *tr =
2109 vlib_add_trace (vm, node, b1, sizeof (*tr));
2110 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2111 sizeof (tr->src.as_u8));
2112 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2113 sizeof (tr->dst.as_u8));
2116 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2118 sr_policy_rewrite_trace_t *tr =
2119 vlib_add_trace (vm, node, b2, sizeof (*tr));
2120 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2121 sizeof (tr->src.as_u8));
2122 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2123 sizeof (tr->dst.as_u8));
2126 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2128 sr_policy_rewrite_trace_t *tr =
2129 vlib_add_trace (vm, node, b3, sizeof (*tr));
2130 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2131 sizeof (tr->src.as_u8));
2132 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2133 sizeof (tr->dst.as_u8));
2138 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2139 n_left_to_next, bi0, bi1, bi2, bi3,
2140 next0, next1, next2, next3);
2143 /* Single loop for potentially the last three packets */
2144 while (n_left_from > 0 && n_left_to_next > 0)
2148 ip6_header_t *ip0 = 0;
2149 ip6_sr_header_t *sr0;
2150 ethernet_header_t *en0;
2151 ip6_sr_policy_t *sp0;
2153 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2161 n_left_to_next -= 1;
2162 b0 = vlib_get_buffer (vm, bi0);
2164 /* Find the SR policy */
2165 sp0 = pool_elt_at_index (sm->sr_policies,
2166 sm->sw_iface_sr_policies[vnet_buffer
2169 flow_label0 = l2_flow_hash (b0);
2171 /* In case there is more than one SL, LB among them */
2172 if (vec_len (sp0->segments_lists) == 1)
2173 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2176 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2177 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2178 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2179 (vec_len (sp0->segments_lists) - 1))];
2182 pool_elt_at_index (sm->sid_lists,
2183 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2184 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2185 vec_len (sl0->rewrite));
2187 en0 = vlib_buffer_get_current (b0);
2189 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2190 sl0->rewrite, vec_len (sl0->rewrite));
2192 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2194 ip0 = vlib_buffer_get_current (b0);
2196 ip0->payload_length =
2197 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2199 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2201 sr0 = (void *) (ip0 + 1);
2202 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2205 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2207 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2208 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2210 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2211 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2213 sr_policy_rewrite_trace_t *tr =
2214 vlib_add_trace (vm, node, b0, sizeof (*tr));
2215 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2216 sizeof (tr->src.as_u8));
2217 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2218 sizeof (tr->dst.as_u8));
2222 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2223 n_left_to_next, bi0, next0);
2226 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2229 /* Update counters */
2230 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2231 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2233 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2234 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2237 return from_frame->n_vectors;
2241 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2242 .function = sr_policy_rewrite_encaps_l2,
2243 .name = "sr-pl-rewrite-encaps-l2",
2244 .vector_size = sizeof (u32),
2245 .format_trace = format_sr_policy_rewrite_trace,
2246 .type = VLIB_NODE_TYPE_INTERNAL,
2247 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2248 .error_strings = sr_policy_rewrite_error_strings,
2249 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2251 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2252 foreach_sr_policy_rewrite_next
2259 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2262 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2263 vlib_frame_t * from_frame)
2265 ip6_sr_main_t *sm = &sr_main;
2266 u32 n_left_from, next_index, *from, *to_next;
2268 from = vlib_frame_vector_args (from_frame);
2269 n_left_from = from_frame->n_vectors;
2271 next_index = node->cached_next_index;
2273 int insert_pkts = 0, bsid_pkts = 0;
2275 while (n_left_from > 0)
2279 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2282 while (n_left_from >= 8 && n_left_to_next >= 4)
2284 u32 bi0, bi1, bi2, bi3;
2285 vlib_buffer_t *b0, *b1, *b2, *b3;
2286 u32 next0, next1, next2, next3;
2287 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2288 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2289 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2290 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2291 u16 new_l0, new_l1, new_l2, new_l3;
2293 /* Prefetch next iteration. */
2295 vlib_buffer_t *p4, *p5, *p6, *p7;
2297 p4 = vlib_get_buffer (vm, from[4]);
2298 p5 = vlib_get_buffer (vm, from[5]);
2299 p6 = vlib_get_buffer (vm, from[6]);
2300 p7 = vlib_get_buffer (vm, from[7]);
2302 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2303 vlib_prefetch_buffer_header (p4, LOAD);
2304 vlib_prefetch_buffer_header (p5, LOAD);
2305 vlib_prefetch_buffer_header (p6, LOAD);
2306 vlib_prefetch_buffer_header (p7, LOAD);
2308 clib_prefetch_store (p4->data);
2309 clib_prefetch_store (p5->data);
2310 clib_prefetch_store (p6->data);
2311 clib_prefetch_store (p7->data);
2314 to_next[0] = bi0 = from[0];
2315 to_next[1] = bi1 = from[1];
2316 to_next[2] = bi2 = from[2];
2317 to_next[3] = bi3 = from[3];
2321 n_left_to_next -= 4;
2323 b0 = vlib_get_buffer (vm, bi0);
2324 b1 = vlib_get_buffer (vm, bi1);
2325 b2 = vlib_get_buffer (vm, bi2);
2326 b3 = vlib_get_buffer (vm, bi3);
2329 pool_elt_at_index (sm->sid_lists,
2330 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2332 pool_elt_at_index (sm->sid_lists,
2333 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2335 pool_elt_at_index (sm->sid_lists,
2336 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2338 pool_elt_at_index (sm->sid_lists,
2339 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2340 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2341 vec_len (sl0->rewrite));
2342 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2343 vec_len (sl1->rewrite));
2344 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2345 vec_len (sl2->rewrite));
2346 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2347 vec_len (sl3->rewrite));
2349 ip0 = vlib_buffer_get_current (b0);
2350 ip1 = vlib_buffer_get_current (b1);
2351 ip2 = vlib_buffer_get_current (b2);
2352 ip3 = vlib_buffer_get_current (b3);
2354 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2356 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2357 ip6_ext_header_len (ip0 + 1));
2359 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2361 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2363 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2364 ip6_ext_header_len (ip1 + 1));
2366 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2368 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2370 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2371 ip6_ext_header_len (ip2 + 1));
2373 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2375 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2377 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2378 ip6_ext_header_len (ip3 + 1));
2380 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2382 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2383 (void *) sr0 - (void *) ip0);
2384 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2385 (void *) sr1 - (void *) ip1);
2386 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2387 (void *) sr2 - (void *) ip2);
2388 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2389 (void *) sr3 - (void *) ip3);
2391 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2392 sl0->rewrite, vec_len (sl0->rewrite));
2393 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2394 sl1->rewrite, vec_len (sl1->rewrite));
2395 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2396 sl2->rewrite, vec_len (sl2->rewrite));
2397 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2398 sl3->rewrite, vec_len (sl3->rewrite));
2400 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2401 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2402 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2403 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2405 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2406 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2407 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2408 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2410 ip0->hop_limit -= 1;
2411 ip1->hop_limit -= 1;
2412 ip2->hop_limit -= 1;
2413 ip3->hop_limit -= 1;
2416 clib_net_to_host_u16 (ip0->payload_length) +
2417 vec_len (sl0->rewrite);
2419 clib_net_to_host_u16 (ip1->payload_length) +
2420 vec_len (sl1->rewrite);
2422 clib_net_to_host_u16 (ip2->payload_length) +
2423 vec_len (sl2->rewrite);
2425 clib_net_to_host_u16 (ip3->payload_length) +
2426 vec_len (sl3->rewrite);
2428 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2429 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2430 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2431 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2433 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2434 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2435 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2436 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2438 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2439 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2440 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2441 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2442 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2443 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2444 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2445 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2447 ip0->dst_address.as_u64[0] =
2448 (sr0->segments + sr0->segments_left)->as_u64[0];
2449 ip0->dst_address.as_u64[1] =
2450 (sr0->segments + sr0->segments_left)->as_u64[1];
2451 ip1->dst_address.as_u64[0] =
2452 (sr1->segments + sr1->segments_left)->as_u64[0];
2453 ip1->dst_address.as_u64[1] =
2454 (sr1->segments + sr1->segments_left)->as_u64[1];
2455 ip2->dst_address.as_u64[0] =
2456 (sr2->segments + sr2->segments_left)->as_u64[0];
2457 ip2->dst_address.as_u64[1] =
2458 (sr2->segments + sr2->segments_left)->as_u64[1];
2459 ip3->dst_address.as_u64[0] =
2460 (sr3->segments + sr3->segments_left)->as_u64[0];
2461 ip3->dst_address.as_u64[1] =
2462 (sr3->segments + sr3->segments_left)->as_u64[1];
2464 ip6_ext_header_t *ip_ext;
2465 if (ip0 + 1 == (void *) sr0)
2467 sr0->protocol = ip0->protocol;
2468 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2472 ip_ext = (void *) (ip0 + 1);
2473 sr0->protocol = ip_ext->next_hdr;
2474 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2477 if (ip1 + 1 == (void *) sr1)
2479 sr1->protocol = ip1->protocol;
2480 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2484 ip_ext = (void *) (ip2 + 1);
2485 sr2->protocol = ip_ext->next_hdr;
2486 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2489 if (ip2 + 1 == (void *) sr2)
2491 sr2->protocol = ip2->protocol;
2492 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2496 ip_ext = (void *) (ip2 + 1);
2497 sr2->protocol = ip_ext->next_hdr;
2498 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2501 if (ip3 + 1 == (void *) sr3)
2503 sr3->protocol = ip3->protocol;
2504 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2508 ip_ext = (void *) (ip3 + 1);
2509 sr3->protocol = ip_ext->next_hdr;
2510 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2515 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2517 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2519 sr_policy_rewrite_trace_t *tr =
2520 vlib_add_trace (vm, node, b0, sizeof (*tr));
2521 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2522 sizeof (tr->src.as_u8));
2523 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2524 sizeof (tr->dst.as_u8));
2527 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2529 sr_policy_rewrite_trace_t *tr =
2530 vlib_add_trace (vm, node, b1, sizeof (*tr));
2531 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2532 sizeof (tr->src.as_u8));
2533 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2534 sizeof (tr->dst.as_u8));
2537 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2539 sr_policy_rewrite_trace_t *tr =
2540 vlib_add_trace (vm, node, b2, sizeof (*tr));
2541 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2542 sizeof (tr->src.as_u8));
2543 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2544 sizeof (tr->dst.as_u8));
2547 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2549 sr_policy_rewrite_trace_t *tr =
2550 vlib_add_trace (vm, node, b3, sizeof (*tr));
2551 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2552 sizeof (tr->src.as_u8));
2553 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2554 sizeof (tr->dst.as_u8));
2558 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2559 n_left_to_next, bi0, bi1, bi2, bi3,
2560 next0, next1, next2, next3);
2563 /* Single loop for potentially the last three packets */
2564 while (n_left_from > 0 && n_left_to_next > 0)
2568 ip6_header_t *ip0 = 0;
2569 ip6_sr_header_t *sr0 = 0;
2571 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2579 n_left_to_next -= 1;
2581 b0 = vlib_get_buffer (vm, bi0);
2583 pool_elt_at_index (sm->sid_lists,
2584 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2585 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2586 vec_len (sl0->rewrite));
2588 ip0 = vlib_buffer_get_current (b0);
2590 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2592 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2593 ip6_ext_header_len (ip0 + 1));
2595 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2597 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2598 (void *) sr0 - (void *) ip0);
2599 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2600 sl0->rewrite, vec_len (sl0->rewrite));
2602 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2604 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2605 ip0->hop_limit -= 1;
2607 clib_net_to_host_u16 (ip0->payload_length) +
2608 vec_len (sl0->rewrite);
2609 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2611 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2612 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2613 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2615 ip0->dst_address.as_u64[0] =
2616 (sr0->segments + sr0->segments_left)->as_u64[0];
2617 ip0->dst_address.as_u64[1] =
2618 (sr0->segments + sr0->segments_left)->as_u64[1];
2620 if (ip0 + 1 == (void *) sr0)
2622 sr0->protocol = ip0->protocol;
2623 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2627 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2628 sr0->protocol = ip_ext->next_hdr;
2629 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2632 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2633 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2635 sr_policy_rewrite_trace_t *tr =
2636 vlib_add_trace (vm, node, b0, sizeof (*tr));
2637 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2638 sizeof (tr->src.as_u8));
2639 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2640 sizeof (tr->dst.as_u8));
2645 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2646 n_left_to_next, bi0, next0);
2649 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2652 /* Update counters */
2653 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2654 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2656 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2657 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2659 return from_frame->n_vectors;
2663 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2664 .function = sr_policy_rewrite_insert,
2665 .name = "sr-pl-rewrite-insert",
2666 .vector_size = sizeof (u32),
2667 .format_trace = format_sr_policy_rewrite_trace,
2668 .type = VLIB_NODE_TYPE_INTERNAL,
2669 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2670 .error_strings = sr_policy_rewrite_error_strings,
2671 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2673 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2674 foreach_sr_policy_rewrite_next
2681 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2684 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2685 vlib_frame_t * from_frame)
2687 ip6_sr_main_t *sm = &sr_main;
2688 u32 n_left_from, next_index, *from, *to_next;
2690 from = vlib_frame_vector_args (from_frame);
2691 n_left_from = from_frame->n_vectors;
2693 next_index = node->cached_next_index;
2695 int insert_pkts = 0, bsid_pkts = 0;
2697 while (n_left_from > 0)
2701 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2704 while (n_left_from >= 8 && n_left_to_next >= 4)
2706 u32 bi0, bi1, bi2, bi3;
2707 vlib_buffer_t *b0, *b1, *b2, *b3;
2708 u32 next0, next1, next2, next3;
2709 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2710 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2711 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2712 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2713 u16 new_l0, new_l1, new_l2, new_l3;
2715 /* Prefetch next iteration. */
2717 vlib_buffer_t *p4, *p5, *p6, *p7;
2719 p4 = vlib_get_buffer (vm, from[4]);
2720 p5 = vlib_get_buffer (vm, from[5]);
2721 p6 = vlib_get_buffer (vm, from[6]);
2722 p7 = vlib_get_buffer (vm, from[7]);
2724 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2725 vlib_prefetch_buffer_header (p4, LOAD);
2726 vlib_prefetch_buffer_header (p5, LOAD);
2727 vlib_prefetch_buffer_header (p6, LOAD);
2728 vlib_prefetch_buffer_header (p7, LOAD);
2730 clib_prefetch_store (p4->data);
2731 clib_prefetch_store (p5->data);
2732 clib_prefetch_store (p6->data);
2733 clib_prefetch_store (p7->data);
2736 to_next[0] = bi0 = from[0];
2737 to_next[1] = bi1 = from[1];
2738 to_next[2] = bi2 = from[2];
2739 to_next[3] = bi3 = from[3];
2743 n_left_to_next -= 4;
2745 b0 = vlib_get_buffer (vm, bi0);
2746 b1 = vlib_get_buffer (vm, bi1);
2747 b2 = vlib_get_buffer (vm, bi2);
2748 b3 = vlib_get_buffer (vm, bi3);
2751 pool_elt_at_index (sm->sid_lists,
2752 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2754 pool_elt_at_index (sm->sid_lists,
2755 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2757 pool_elt_at_index (sm->sid_lists,
2758 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2760 pool_elt_at_index (sm->sid_lists,
2761 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2762 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2763 vec_len (sl0->rewrite_bsid));
2764 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2765 vec_len (sl1->rewrite_bsid));
2766 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2767 vec_len (sl2->rewrite_bsid));
2768 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2769 vec_len (sl3->rewrite_bsid));
2771 ip0 = vlib_buffer_get_current (b0);
2772 ip1 = vlib_buffer_get_current (b1);
2773 ip2 = vlib_buffer_get_current (b2);
2774 ip3 = vlib_buffer_get_current (b3);
2776 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2778 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2779 ip6_ext_header_len (ip0 + 1));
2781 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2783 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2785 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2786 ip6_ext_header_len (ip1 + 1));
2788 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2790 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2792 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2793 ip6_ext_header_len (ip2 + 1));
2795 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2797 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2799 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2800 ip6_ext_header_len (ip3 + 1));
2802 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2804 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2805 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2806 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2807 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2808 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2809 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2810 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2811 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2813 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2814 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2815 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2816 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2817 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2818 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2819 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2820 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2822 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2823 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2824 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2825 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2827 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2828 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2829 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2830 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2832 ip0->hop_limit -= 1;
2833 ip1->hop_limit -= 1;
2834 ip2->hop_limit -= 1;
2835 ip3->hop_limit -= 1;
2838 clib_net_to_host_u16 (ip0->payload_length) +
2839 vec_len (sl0->rewrite_bsid);
2841 clib_net_to_host_u16 (ip1->payload_length) +
2842 vec_len (sl1->rewrite_bsid);
2844 clib_net_to_host_u16 (ip2->payload_length) +
2845 vec_len (sl2->rewrite_bsid);
2847 clib_net_to_host_u16 (ip3->payload_length) +
2848 vec_len (sl3->rewrite_bsid);
2850 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2851 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2852 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2853 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2855 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2856 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2857 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2858 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2860 ip0->dst_address.as_u64[0] =
2861 (sr0->segments + sr0->segments_left)->as_u64[0];
2862 ip0->dst_address.as_u64[1] =
2863 (sr0->segments + sr0->segments_left)->as_u64[1];
2864 ip1->dst_address.as_u64[0] =
2865 (sr1->segments + sr1->segments_left)->as_u64[0];
2866 ip1->dst_address.as_u64[1] =
2867 (sr1->segments + sr1->segments_left)->as_u64[1];
2868 ip2->dst_address.as_u64[0] =
2869 (sr2->segments + sr2->segments_left)->as_u64[0];
2870 ip2->dst_address.as_u64[1] =
2871 (sr2->segments + sr2->segments_left)->as_u64[1];
2872 ip3->dst_address.as_u64[0] =
2873 (sr3->segments + sr3->segments_left)->as_u64[0];
2874 ip3->dst_address.as_u64[1] =
2875 (sr3->segments + sr3->segments_left)->as_u64[1];
2877 ip6_ext_header_t *ip_ext;
2878 if (ip0 + 1 == (void *) sr0)
2880 sr0->protocol = ip0->protocol;
2881 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2885 ip_ext = (void *) (ip0 + 1);
2886 sr0->protocol = ip_ext->next_hdr;
2887 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2890 if (ip1 + 1 == (void *) sr1)
2892 sr1->protocol = ip1->protocol;
2893 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2897 ip_ext = (void *) (ip2 + 1);
2898 sr2->protocol = ip_ext->next_hdr;
2899 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2902 if (ip2 + 1 == (void *) sr2)
2904 sr2->protocol = ip2->protocol;
2905 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2909 ip_ext = (void *) (ip2 + 1);
2910 sr2->protocol = ip_ext->next_hdr;
2911 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2914 if (ip3 + 1 == (void *) sr3)
2916 sr3->protocol = ip3->protocol;
2917 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2921 ip_ext = (void *) (ip3 + 1);
2922 sr3->protocol = ip_ext->next_hdr;
2923 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2928 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2930 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2932 sr_policy_rewrite_trace_t *tr =
2933 vlib_add_trace (vm, node, b0, sizeof (*tr));
2934 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2935 sizeof (tr->src.as_u8));
2936 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2937 sizeof (tr->dst.as_u8));
2940 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2942 sr_policy_rewrite_trace_t *tr =
2943 vlib_add_trace (vm, node, b1, sizeof (*tr));
2944 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2945 sizeof (tr->src.as_u8));
2946 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2947 sizeof (tr->dst.as_u8));
2950 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2952 sr_policy_rewrite_trace_t *tr =
2953 vlib_add_trace (vm, node, b2, sizeof (*tr));
2954 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2955 sizeof (tr->src.as_u8));
2956 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2957 sizeof (tr->dst.as_u8));
2960 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2962 sr_policy_rewrite_trace_t *tr =
2963 vlib_add_trace (vm, node, b3, sizeof (*tr));
2964 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2965 sizeof (tr->src.as_u8));
2966 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2967 sizeof (tr->dst.as_u8));
2971 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2972 n_left_to_next, bi0, bi1, bi2, bi3,
2973 next0, next1, next2, next3);
2976 /* Single loop for potentially the last three packets */
2977 while (n_left_from > 0 && n_left_to_next > 0)
2981 ip6_header_t *ip0 = 0;
2982 ip6_sr_header_t *sr0 = 0;
2984 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2992 n_left_to_next -= 1;
2994 b0 = vlib_get_buffer (vm, bi0);
2996 pool_elt_at_index (sm->sid_lists,
2997 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2998 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2999 vec_len (sl0->rewrite_bsid));
3001 ip0 = vlib_buffer_get_current (b0);
3003 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3005 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3006 ip6_ext_header_len (ip0 + 1));
3008 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3010 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3011 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3012 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3013 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3015 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3017 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3018 ip0->hop_limit -= 1;
3020 clib_net_to_host_u16 (ip0->payload_length) +
3021 vec_len (sl0->rewrite_bsid);
3022 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3024 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3026 ip0->dst_address.as_u64[0] =
3027 (sr0->segments + sr0->segments_left)->as_u64[0];
3028 ip0->dst_address.as_u64[1] =
3029 (sr0->segments + sr0->segments_left)->as_u64[1];
3031 if (ip0 + 1 == (void *) sr0)
3033 sr0->protocol = ip0->protocol;
3034 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3038 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3039 sr0->protocol = ip_ext->next_hdr;
3040 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3043 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3044 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3046 sr_policy_rewrite_trace_t *tr =
3047 vlib_add_trace (vm, node, b0, sizeof (*tr));
3048 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3049 sizeof (tr->src.as_u8));
3050 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3051 sizeof (tr->dst.as_u8));
3056 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3057 n_left_to_next, bi0, next0);
3060 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3063 /* Update counters */
3064 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3065 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3067 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3068 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3070 return from_frame->n_vectors;
3074 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3075 .function = sr_policy_rewrite_b_insert,
3076 .name = "sr-pl-rewrite-b-insert",
3077 .vector_size = sizeof (u32),
3078 .format_trace = format_sr_policy_rewrite_trace,
3079 .type = VLIB_NODE_TYPE_INTERNAL,
3080 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3081 .error_strings = sr_policy_rewrite_error_strings,
3082 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3084 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3085 foreach_sr_policy_rewrite_next
3092 * @brief Function BSID encapsulation
3094 static_always_inline void
3095 end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3096 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3097 u32 *next0, u8 policy_type)
3099 ip6_address_t *new_dst0;
3101 if (PREDICT_FALSE (!sr0))
3102 goto error_bsid_encaps;
3104 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3106 if (PREDICT_TRUE (sr0->segments_left != 0))
3108 sr0->segments_left -= 1;
3109 new_dst0 = (ip6_address_t *) (sr0->segments);
3110 new_dst0 += sr0->segments_left;
3111 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3112 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3118 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3119 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3123 * @brief Graph node for applying a SR policy BSID - Encapsulation
3126 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3127 vlib_frame_t * from_frame)
3129 ip6_sr_main_t *sm = &sr_main;
3130 u32 n_left_from, next_index, *from, *to_next;
3132 from = vlib_frame_vector_args (from_frame);
3133 n_left_from = from_frame->n_vectors;
3135 next_index = node->cached_next_index;
3137 int encap_pkts = 0, bsid_pkts = 0;
3139 while (n_left_from > 0)
3143 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3146 while (n_left_from >= 8 && n_left_to_next >= 4)
3148 u32 bi0, bi1, bi2, bi3;
3149 vlib_buffer_t *b0, *b1, *b2, *b3;
3150 u32 next0, next1, next2, next3;
3151 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3152 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3153 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3154 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3155 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3157 /* Prefetch next iteration. */
3159 vlib_buffer_t *p4, *p5, *p6, *p7;
3161 p4 = vlib_get_buffer (vm, from[4]);
3162 p5 = vlib_get_buffer (vm, from[5]);
3163 p6 = vlib_get_buffer (vm, from[6]);
3164 p7 = vlib_get_buffer (vm, from[7]);
3166 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3167 vlib_prefetch_buffer_header (p4, LOAD);
3168 vlib_prefetch_buffer_header (p5, LOAD);
3169 vlib_prefetch_buffer_header (p6, LOAD);
3170 vlib_prefetch_buffer_header (p7, LOAD);
3172 clib_prefetch_store (p4->data);
3173 clib_prefetch_store (p5->data);
3174 clib_prefetch_store (p6->data);
3175 clib_prefetch_store (p7->data);
3178 to_next[0] = bi0 = from[0];
3179 to_next[1] = bi1 = from[1];
3180 to_next[2] = bi2 = from[2];
3181 to_next[3] = bi3 = from[3];
3185 n_left_to_next -= 4;
3187 b0 = vlib_get_buffer (vm, bi0);
3188 b1 = vlib_get_buffer (vm, bi1);
3189 b2 = vlib_get_buffer (vm, bi2);
3190 b3 = vlib_get_buffer (vm, bi3);
3193 pool_elt_at_index (sm->sid_lists,
3194 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3196 pool_elt_at_index (sm->sid_lists,
3197 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3199 pool_elt_at_index (sm->sid_lists,
3200 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3202 pool_elt_at_index (sm->sid_lists,
3203 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3204 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3205 vec_len (sl0->rewrite));
3206 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3207 vec_len (sl1->rewrite));
3208 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3209 vec_len (sl2->rewrite));
3210 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3211 vec_len (sl3->rewrite));
3213 ip0_encap = vlib_buffer_get_current (b0);
3214 ip1_encap = vlib_buffer_get_current (b1);
3215 ip2_encap = vlib_buffer_get_current (b2);
3216 ip3_encap = vlib_buffer_get_current (b3);
3219 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3222 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3225 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3228 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3231 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3233 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3235 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3237 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3240 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3241 sl0->rewrite, vec_len (sl0->rewrite));
3242 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3243 sl1->rewrite, vec_len (sl1->rewrite));
3244 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3245 sl2->rewrite, vec_len (sl2->rewrite));
3246 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3247 sl3->rewrite, vec_len (sl3->rewrite));
3249 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3250 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3251 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3252 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3254 ip0 = vlib_buffer_get_current (b0);
3255 ip1 = vlib_buffer_get_current (b1);
3256 ip2 = vlib_buffer_get_current (b2);
3257 ip3 = vlib_buffer_get_current (b3);
3259 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3260 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3261 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3262 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
3264 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3266 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3268 sr_policy_rewrite_trace_t *tr =
3269 vlib_add_trace (vm, node, b0, sizeof (*tr));
3270 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3271 sizeof (tr->src.as_u8));
3272 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3273 sizeof (tr->dst.as_u8));
3276 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3278 sr_policy_rewrite_trace_t *tr =
3279 vlib_add_trace (vm, node, b1, sizeof (*tr));
3280 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3281 sizeof (tr->src.as_u8));
3282 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3283 sizeof (tr->dst.as_u8));
3286 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3288 sr_policy_rewrite_trace_t *tr =
3289 vlib_add_trace (vm, node, b2, sizeof (*tr));
3290 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3291 sizeof (tr->src.as_u8));
3292 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3293 sizeof (tr->dst.as_u8));
3296 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3298 sr_policy_rewrite_trace_t *tr =
3299 vlib_add_trace (vm, node, b3, sizeof (*tr));
3300 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3301 sizeof (tr->src.as_u8));
3302 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3303 sizeof (tr->dst.as_u8));
3308 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3309 n_left_to_next, bi0, bi1, bi2, bi3,
3310 next0, next1, next2, next3);
3313 /* Single loop for potentially the last three packets */
3314 while (n_left_from > 0 && n_left_to_next > 0)
3318 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3319 ip6_sr_header_t *sr0;
3321 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3328 n_left_to_next -= 1;
3329 b0 = vlib_get_buffer (vm, bi0);
3332 pool_elt_at_index (sm->sid_lists,
3333 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3334 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3335 vec_len (sl0->rewrite));
3337 ip0_encap = vlib_buffer_get_current (b0);
3339 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3341 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3344 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3345 sl0->rewrite, vec_len (sl0->rewrite));
3346 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3348 ip0 = vlib_buffer_get_current (b0);
3350 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3352 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3353 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3355 sr_policy_rewrite_trace_t *tr =
3356 vlib_add_trace (vm, node, b0, sizeof (*tr));
3357 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3358 sizeof (tr->src.as_u8));
3359 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3360 sizeof (tr->dst.as_u8));
3364 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3365 n_left_to_next, bi0, next0);
3368 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3371 /* Update counters */
3372 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3373 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3375 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3376 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3379 return from_frame->n_vectors;
3383 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3384 .function = sr_policy_rewrite_b_encaps,
3385 .name = "sr-pl-rewrite-b-encaps",
3386 .vector_size = sizeof (u32),
3387 .format_trace = format_sr_policy_rewrite_trace,
3388 .type = VLIB_NODE_TYPE_INTERNAL,
3389 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3390 .error_strings = sr_policy_rewrite_error_strings,
3391 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3393 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3394 foreach_sr_policy_rewrite_next
3400 /*************************** SR Policy plugins ******************************/
3402 * @brief SR Policy plugin registry
3405 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3406 u8 * keyword_str, u8 * def_str,
3407 u8 * params_str, u8 prefix_length,
3409 format_function_t * ls_format,
3410 unformat_function_t * ls_unformat,
3411 sr_p_plugin_callback_t * creation_fn,
3412 sr_p_plugin_callback_t * removal_fn)
3414 ip6_sr_main_t *sm = &sr_main;
3417 sr_policy_fn_registration_t *plugin;
3419 /* Did this function exist? If so update it */
3420 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3423 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3425 /* Else create a new one and set hash key */
3428 pool_get (sm->policy_plugin_functions, plugin);
3429 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3430 plugin - sm->policy_plugin_functions);
3433 clib_memset (plugin, 0, sizeof (*plugin));
3435 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3436 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3437 plugin->prefix_length = prefix_length;
3438 plugin->ls_format = ls_format;
3439 plugin->ls_unformat = ls_unformat;
3440 plugin->creation = creation_fn;
3441 plugin->removal = removal_fn;
3442 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3443 plugin->function_name = format (0, "%s%c", fn_name, 0);
3444 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3445 plugin->def_str = format (0, "%s%c", def_str, 0);
3446 plugin->params_str = format (0, "%s%c", params_str, 0);
3448 return plugin->sr_policy_function_number;
3452 * @brief CLI function to 'show' all available SR LocalSID behaviors
3454 static clib_error_t *
3455 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3456 unformat_input_t * input,
3457 vlib_cli_command_t * cmd)
3459 ip6_sr_main_t *sm = &sr_main;
3460 sr_policy_fn_registration_t *plugin;
3461 sr_policy_fn_registration_t **plugins_vec = 0;
3464 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3467 pool_foreach (plugin, sm->policy_plugin_functions)
3468 { vec_add1 (plugins_vec, plugin); }
3471 vlib_cli_output (vm, "Plugin behaviors:\n");
3472 for (i = 0; i < vec_len (plugins_vec); i++)
3474 plugin = plugins_vec[i];
3475 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3477 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3483 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3484 .path = "show sr policy behaviors",
3485 .short_help = "show sr policy behaviors",
3486 .function = show_sr_policy_behaviors_command_fn,
3490 /*************************** SR Segment Lists DPOs ****************************/
3492 format_sr_segment_list_dpo (u8 * s, va_list * args)
3494 ip6_sr_main_t *sm = &sr_main;
3495 ip6_address_t *addr;
3498 index_t index = va_arg (*args, index_t);
3499 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3500 s = format (s, "SR: Segment List index:[%d]", index);
3501 s = format (s, "\n\tSegments:");
3503 sl = pool_elt_at_index (sm->sid_lists, index);
3505 s = format (s, "< ");
3506 vec_foreach (addr, sl->segments)
3508 s = format (s, "%U, ", format_ip6_address, addr);
3510 s = format (s, "\b\b > - ");
3511 s = format (s, "Weight: %u", sl->weight);
3516 const static dpo_vft_t sr_policy_rewrite_vft = {
3517 .dv_lock = sr_dpo_lock,
3518 .dv_unlock = sr_dpo_unlock,
3519 .dv_format = format_sr_segment_list_dpo,
3522 const static char *const sr_pr_encaps_ip6_nodes[] = {
3523 "sr-pl-rewrite-encaps",
3527 const static char *const sr_pr_encaps_ip4_nodes[] = {
3528 "sr-pl-rewrite-encaps-v4",
3532 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3533 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3534 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3537 const static char *const sr_pr_insert_ip6_nodes[] = {
3538 "sr-pl-rewrite-insert",
3542 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3543 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3546 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3547 "sr-pl-rewrite-b-insert",
3551 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3552 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3555 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3556 "sr-pl-rewrite-b-encaps",
3560 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3561 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3564 /********************* SR Policy Rewrite initialization ***********************/
3566 * @brief SR Policy Rewrite initialization
3569 sr_policy_rewrite_init (vlib_main_t * vm)
3571 ip6_sr_main_t *sm = &sr_main;
3573 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3574 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3575 sizeof (ip6_address_t));
3577 /* Init SR VPO DPOs type */
3578 sr_pr_encaps_dpo_type =
3579 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3581 sr_pr_insert_dpo_type =
3582 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3584 sr_pr_bsid_encaps_dpo_type =
3585 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3587 sr_pr_bsid_insert_dpo_type =
3588 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3590 /* Register the L2 encaps node used in HW redirect */
3591 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3593 sm->fib_table_ip6 = (u32) ~ 0;
3594 sm->fib_table_ip4 = (u32) ~ 0;
3599 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3603 * fd.io coding-style-patch-verification: ON
3606 * eval: (c-set-style "gnu")