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/ip.h>
45 #include <vnet/srv6/sr_packet.h>
46 #include <vnet/ip/ip6_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));
122 static clib_error_t *
123 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
124 vlib_cli_command_t * cmd)
126 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
129 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
132 return clib_error_return (0, "No address specified");
134 return clib_error_return (0, "No address specified");
138 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
139 .path = "set sr encaps source",
140 .short_help = "set sr encaps source addr <ip6_addr>",
141 .function = set_sr_src_command_fn,
145 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
148 sr_set_hop_limit (u8 hop_limit)
150 sr_pr_encaps_hop_limit = hop_limit;
154 sr_get_hop_limit (void)
156 return sr_pr_encaps_hop_limit;
159 static clib_error_t *
160 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
161 vlib_cli_command_t * cmd)
163 int hop_limit = sr_get_hop_limit ();
165 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
166 return clib_error_return (0, "No value specified");
167 if (!unformat (input, "%d", &hop_limit))
168 return clib_error_return (0, "Invalid value");
169 if (hop_limit <= 0 || hop_limit > 255)
170 return clib_error_return (0, "Value out of range [1-255]");
171 sr_pr_encaps_hop_limit = (u8) hop_limit;
176 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
177 .path = "set sr encaps hop-limit",
178 .short_help = "set sr encaps hop-limit <value>",
179 .function = set_sr_hop_limit_command_fn,
183 /*********************** SR rewrite string computation ************************/
185 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
187 * @param sl is a vector of IPv6 addresses composing the Segment List
189 * @return precomputed rewrite string for encapsulation
192 compute_rewrite_encaps (ip6_address_t * sl)
195 ip6_sr_header_t *srh;
196 ip6_address_t *addrp, *this_address;
197 u32 header_length = 0;
201 header_length += IPv6_DEFAULT_HEADER_LENGTH;
202 if (vec_len (sl) > 1)
204 header_length += sizeof (ip6_sr_header_t);
205 header_length += vec_len (sl) * sizeof (ip6_address_t);
208 vec_validate (rs, header_length - 1);
210 iph = (ip6_header_t *) rs;
211 iph->ip_version_traffic_class_and_flow_label =
212 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
213 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
214 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
215 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
216 iph->protocol = IP_PROTOCOL_IPV6;
217 iph->hop_limit = sr_pr_encaps_hop_limit;
219 if (vec_len (sl) > 1)
221 srh = (ip6_sr_header_t *) (iph + 1);
222 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
223 srh->protocol = IP_PROTOCOL_IPV6;
224 srh->type = ROUTING_HEADER_TYPE_SR;
225 srh->segments_left = vec_len (sl) - 1;
226 srh->last_entry = vec_len (sl) - 1;
227 srh->length = ((sizeof (ip6_sr_header_t) +
228 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
231 addrp = srh->segments + vec_len (sl) - 1;
232 vec_foreach (this_address, sl)
234 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
235 sizeof (ip6_address_t));
239 iph->dst_address.as_u64[0] = sl->as_u64[0];
240 iph->dst_address.as_u64[1] = sl->as_u64[1];
245 * @brief SR rewrite string computation for SRH insertion (inline)
247 * @param sl is a vector of IPv6 addresses composing the Segment List
249 * @return precomputed rewrite string for SRH insertion
252 compute_rewrite_insert (ip6_address_t * sl)
254 ip6_sr_header_t *srh;
255 ip6_address_t *addrp, *this_address;
256 u32 header_length = 0;
260 header_length += sizeof (ip6_sr_header_t);
261 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
263 vec_validate (rs, header_length - 1);
265 srh = (ip6_sr_header_t *) rs;
266 srh->type = ROUTING_HEADER_TYPE_SR;
267 srh->segments_left = vec_len (sl);
268 srh->last_entry = vec_len (sl);
269 srh->length = ((sizeof (ip6_sr_header_t) +
270 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
273 addrp = srh->segments + vec_len (sl);
274 vec_foreach (this_address, sl)
276 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
277 sizeof (ip6_address_t));
284 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
286 * @param sl is a vector of IPv6 addresses composing the Segment List
288 * @return precomputed rewrite string for SRH insertion with BSID
291 compute_rewrite_bsid (ip6_address_t * sl)
293 ip6_sr_header_t *srh;
294 ip6_address_t *addrp, *this_address;
295 u32 header_length = 0;
299 header_length += sizeof (ip6_sr_header_t);
300 header_length += vec_len (sl) * sizeof (ip6_address_t);
302 vec_validate (rs, header_length - 1);
304 srh = (ip6_sr_header_t *) rs;
305 srh->type = ROUTING_HEADER_TYPE_SR;
306 srh->segments_left = vec_len (sl) - 1;
307 srh->last_entry = vec_len (sl) - 1;
308 srh->length = ((sizeof (ip6_sr_header_t) +
309 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
312 addrp = srh->segments + vec_len (sl) - 1;
313 vec_foreach (this_address, sl)
315 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
316 sizeof (ip6_address_t));
322 /*************************** SR LB helper functions **************************/
324 * @brief Creates a Segment List and adds it to an SR policy
326 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
327 * not necessarily unique. Hence there might be two Segment List within the
328 * same SR Policy with exactly the same segments and same weight.
330 * @param sr_policy is the SR policy where the SL will be added
331 * @param sl is a vector of IPv6 addresses composing the Segment List
332 * @param weight is the weight of the SegmentList (for load-balancing purposes)
333 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
335 * @return pointer to the just created segment list
337 static inline ip6_sr_sl_t *
338 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
341 ip6_sr_main_t *sm = &sr_main;
342 ip6_sr_sl_t *segment_list;
343 sr_policy_fn_registration_t *plugin = 0;
345 pool_get (sm->sid_lists, segment_list);
346 clib_memset (segment_list, 0, sizeof (*segment_list));
348 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
350 /* Fill in segment list */
351 segment_list->weight =
352 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
354 segment_list->segments = vec_dup (sl);
358 segment_list->rewrite = compute_rewrite_encaps (sl);
359 segment_list->rewrite_bsid = segment_list->rewrite;
363 segment_list->rewrite = compute_rewrite_insert (sl);
364 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
367 if (sr_policy->plugin)
370 pool_elt_at_index (sm->policy_plugin_functions,
371 sr_policy->plugin - SR_BEHAVIOR_LAST);
373 segment_list->plugin = sr_policy->plugin;
374 segment_list->plugin_mem = sr_policy->plugin_mem;
376 plugin->creation (sr_policy);
380 dpo_reset (&segment_list->bsid_dpo);
381 dpo_reset (&segment_list->ip6_dpo);
382 dpo_reset (&segment_list->ip4_dpo);
386 if (!sr_policy->plugin)
388 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
389 DPO_PROTO_IP6, segment_list - sm->sid_lists);
390 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
391 DPO_PROTO_IP4, segment_list - sm->sid_lists);
392 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
393 DPO_PROTO_IP6, segment_list - sm->sid_lists);
397 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
398 segment_list - sm->sid_lists);
399 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
400 segment_list - sm->sid_lists);
401 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
402 segment_list - sm->sid_lists);
407 if (!sr_policy->plugin)
409 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
410 DPO_PROTO_IP6, segment_list - sm->sid_lists);
411 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
412 DPO_PROTO_IP6, segment_list - sm->sid_lists);
416 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
417 segment_list - sm->sid_lists);
418 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
419 segment_list - sm->sid_lists);
427 * @brief Updates the Load Balancer after an SR Policy change
429 * @param sr_policy is the modified SR Policy
432 update_lb (ip6_sr_policy_t * sr_policy)
434 flow_hash_config_t fhc;
436 ip6_sr_sl_t *segment_list;
437 ip6_sr_main_t *sm = &sr_main;
438 load_balance_path_t path;
439 path.path_index = FIB_NODE_INDEX_INVALID;
440 load_balance_path_t *ip4_path_vector = 0;
441 load_balance_path_t *ip6_path_vector = 0;
442 load_balance_path_t *b_path_vector = 0;
444 /* In case LB does not exist, create it */
445 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
448 .fp_proto = FIB_PROTOCOL_IP6,
451 .ip6 = sr_policy->bsid,
455 /* Add FIB entry for BSID */
456 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
459 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
460 load_balance_create (0, DPO_PROTO_IP6, fhc));
462 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
463 load_balance_create (0, DPO_PROTO_IP6, fhc));
465 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
466 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
467 sr_policy->fib_table),
469 FIB_ENTRY_FLAG_EXCLUSIVE,
470 &sr_policy->bsid_dpo);
472 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->ip6_dpo);
478 if (sr_policy->is_encap)
480 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
481 load_balance_create (0, DPO_PROTO_IP4, fhc));
483 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
486 FIB_ENTRY_FLAG_EXCLUSIVE,
487 &sr_policy->ip4_dpo);
492 /* Create the LB path vector */
493 vec_foreach (sl_index, sr_policy->segments_lists)
495 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
496 path.path_dpo = segment_list->bsid_dpo;
497 path.path_weight = segment_list->weight;
498 vec_add1 (b_path_vector, path);
499 path.path_dpo = segment_list->ip6_dpo;
500 vec_add1 (ip6_path_vector, path);
501 if (sr_policy->is_encap)
503 path.path_dpo = segment_list->ip4_dpo;
504 vec_add1 (ip4_path_vector, path);
508 /* Update LB multipath */
509 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
510 LOAD_BALANCE_FLAG_NONE);
511 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
512 LOAD_BALANCE_FLAG_NONE);
513 if (sr_policy->is_encap)
514 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
515 LOAD_BALANCE_FLAG_NONE);
518 vec_free (b_path_vector);
519 vec_free (ip6_path_vector);
520 vec_free (ip4_path_vector);
524 * @brief Updates the Replicate DPO after an SR Policy change
526 * @param sr_policy is the modified SR Policy (type spray)
529 update_replicate (ip6_sr_policy_t * sr_policy)
532 ip6_sr_sl_t *segment_list;
533 ip6_sr_main_t *sm = &sr_main;
534 load_balance_path_t path;
535 path.path_index = FIB_NODE_INDEX_INVALID;
536 load_balance_path_t *b_path_vector = 0;
537 load_balance_path_t *ip6_path_vector = 0;
538 load_balance_path_t *ip4_path_vector = 0;
540 /* In case LB does not exist, create it */
541 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
543 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
544 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
546 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
547 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
549 /* Update FIB entry's DPO to point to SR without LB */
551 .fp_proto = FIB_PROTOCOL_IP6,
554 .ip6 = sr_policy->bsid,
557 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
558 sr_policy->fib_table),
560 FIB_ENTRY_FLAG_EXCLUSIVE,
561 &sr_policy->bsid_dpo);
563 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
566 FIB_ENTRY_FLAG_EXCLUSIVE,
567 &sr_policy->ip6_dpo);
569 if (sr_policy->is_encap)
571 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
572 replicate_create (0, DPO_PROTO_IP4));
574 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
577 FIB_ENTRY_FLAG_EXCLUSIVE,
578 &sr_policy->ip4_dpo);
583 /* Create the replicate path vector */
584 path.path_weight = 1;
585 vec_foreach (sl_index, sr_policy->segments_lists)
587 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
588 path.path_dpo = segment_list->bsid_dpo;
589 vec_add1 (b_path_vector, path);
590 path.path_dpo = segment_list->ip6_dpo;
591 vec_add1 (ip6_path_vector, path);
592 if (sr_policy->is_encap)
594 path.path_dpo = segment_list->ip4_dpo;
595 vec_add1 (ip4_path_vector, path);
599 /* Update replicate multipath */
600 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
601 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
602 if (sr_policy->is_encap)
603 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
606 /******************************* SR rewrite API *******************************/
607 /* Three functions for handling sr policies:
611 * All of them are API. CLI function on sr_policy_command_fn */
614 * @brief Create a new SR policy
616 * @param bsid is the bindingSID of the SR Policy
617 * @param segments is a vector of IPv6 address composing the segment list
618 * @param weight is the weight of the sid list. optional.
619 * @param behavior is the behavior of the SR policy. (default//spray)
620 * @param fib_table is the VRF where to install the FIB entry for the BSID
621 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
623 * @return 0 if correct, else error
626 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
627 u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
628 u16 plugin, void *ls_plugin_mem)
630 ip6_sr_main_t *sm = &sr_main;
631 ip6_sr_policy_t *sr_policy = 0;
634 /* Search for existing keys (BSID) */
635 p = mhash_get (&sm->sr_policies_index_hash, bsid);
638 /* Add SR policy that already exists; complain */
642 /* Search collision in FIB entries */
643 /* Explanation: It might be possible that some other entity has already
644 * created a route for the BSID. This in theory is impossible, but in
645 * practise we could see it. Assert it and scream if needed */
647 .fp_proto = FIB_PROTOCOL_IP6,
654 /* Lookup the FIB index associated to the table selected */
655 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
656 (fib_table != (u32) ~ 0 ? fib_table : 0));
660 /* Lookup whether there exists an entry for the BSID */
661 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
662 if (FIB_NODE_INDEX_INVALID != fei)
663 return -12; //There is an entry for such lookup
665 /* Add an SR policy object */
666 pool_get (sm->sr_policies, sr_policy);
667 clib_memset (sr_policy, 0, sizeof (*sr_policy));
668 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
669 sr_policy->type = behavior;
670 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
671 sr_policy->is_encap = is_encap;
675 sr_policy->plugin = plugin;
676 sr_policy->plugin_mem = ls_plugin_mem;
680 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
683 /* Create a segment list and add the index to the SR policy */
684 create_sl (sr_policy, segments, weight, is_encap);
686 /* If FIB doesnt exist, create them */
687 if (sm->fib_table_ip6 == (u32) ~ 0)
689 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
691 "SRv6 steering of IP6 prefixes through BSIDs");
692 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
694 "SRv6 steering of IP4 prefixes through BSIDs");
697 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
698 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
699 update_lb (sr_policy);
700 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
701 update_replicate (sr_policy);
706 * @brief Delete a SR policy
708 * @param bsid is the bindingSID of the SR Policy
709 * @param index is the index of the SR policy
711 * @return 0 if correct, else error
714 sr_policy_del (ip6_address_t * bsid, u32 index)
716 ip6_sr_main_t *sm = &sr_main;
717 ip6_sr_policy_t *sr_policy = 0;
718 ip6_sr_sl_t *segment_list;
724 p = mhash_get (&sm->sr_policies_index_hash, bsid);
726 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
732 sr_policy = pool_elt_at_index (sm->sr_policies, index);
737 /* Remove BindingSID FIB entry */
739 .fp_proto = FIB_PROTOCOL_IP6,
742 .ip6 = sr_policy->bsid,
747 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
748 sr_policy->fib_table),
749 &pfx, FIB_SOURCE_SR);
751 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
753 if (sr_policy->is_encap)
754 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
756 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
758 dpo_reset (&sr_policy->bsid_dpo);
759 dpo_reset (&sr_policy->ip4_dpo);
760 dpo_reset (&sr_policy->ip6_dpo);
763 /* Clean SID Lists */
764 vec_foreach (sl_index, sr_policy->segments_lists)
766 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
767 vec_free (segment_list->segments);
768 vec_free (segment_list->rewrite);
769 if (!sr_policy->is_encap)
770 vec_free (segment_list->rewrite_bsid);
771 pool_put_index (sm->sid_lists, *sl_index);
774 if (sr_policy->plugin)
776 sr_policy_fn_registration_t *plugin = 0;
779 pool_elt_at_index (sm->policy_plugin_functions,
780 sr_policy->plugin - SR_BEHAVIOR_LAST);
782 plugin->removal (sr_policy);
783 sr_policy->plugin = 0;
784 sr_policy->plugin_mem = NULL;
787 /* Remove SR policy entry */
788 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
789 pool_put (sm->sr_policies, sr_policy);
791 /* If FIB empty unlock it */
792 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
794 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
795 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
796 sm->fib_table_ip6 = (u32) ~ 0;
797 sm->fib_table_ip4 = (u32) ~ 0;
804 * @brief Modify an existing SR policy
806 * The possible modifications are adding a new Segment List, modifying an
807 * existing Segment List (modify the weight only) and delete a given
808 * Segment List from the SR Policy.
810 * @param bsid is the bindingSID of the SR Policy
811 * @param index is the index of the SR policy
812 * @param fib_table is the VRF where to install the FIB entry for the BSID
813 * @param operation is the operation to perform (among the top ones)
814 * @param segments is a vector of IPv6 address composing the segment list
815 * @param sl_index is the index of the Segment List to modify/delete
816 * @param weight is the weight of the sid list. optional.
817 * @param is_encap Mode. Encapsulation or SRH insertion.
819 * @return 0 if correct, else error
822 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
823 u8 operation, ip6_address_t * segments, u32 sl_index,
826 ip6_sr_main_t *sm = &sr_main;
827 ip6_sr_policy_t *sr_policy = 0;
828 ip6_sr_sl_t *segment_list;
829 u32 *sl_index_iterate;
834 p = mhash_get (&sm->sr_policies_index_hash, bsid);
836 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
842 sr_policy = pool_elt_at_index (sm->sr_policies, index);
847 if (operation == 1) /* Add SR List to an existing SR policy */
849 /* Create the new SL */
851 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
853 /* Create a new LB DPO */
854 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
855 update_lb (sr_policy);
856 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
857 update_replicate (sr_policy);
859 else if (operation == 2) /* Delete SR List from an existing SR policy */
861 /* Check that currently there are more than one SID list */
862 if (vec_len (sr_policy->segments_lists) == 1)
865 /* Check that the SR list does exist and is assigned to the sr policy */
866 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
867 if (*sl_index_iterate == sl_index)
870 if (*sl_index_iterate != sl_index)
873 /* Remove the lucky SR list that is being kicked out */
874 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
875 vec_free (segment_list->segments);
876 vec_free (segment_list->rewrite);
877 if (!sr_policy->is_encap)
878 vec_free (segment_list->rewrite_bsid);
879 pool_put_index (sm->sid_lists, sl_index);
880 vec_del1 (sr_policy->segments_lists,
881 sl_index_iterate - sr_policy->segments_lists);
883 /* Create a new LB DPO */
884 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
885 update_lb (sr_policy);
886 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
887 update_replicate (sr_policy);
889 else if (operation == 3) /* Modify the weight of an existing SR List */
891 /* Find the corresponding SL */
892 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
893 if (*sl_index_iterate == sl_index)
896 if (*sl_index_iterate != sl_index)
899 /* Change the weight */
900 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
901 segment_list->weight = weight;
904 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
905 update_lb (sr_policy);
907 else /* Incorrect op. */
914 * @brief CLI for 'sr policies' command family
916 static clib_error_t *
917 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
918 vlib_cli_command_t * cmd)
920 ip6_sr_main_t *sm = &sr_main;
922 char is_del = 0, is_add = 0, is_mod = 0;
924 ip6_address_t bsid, next_address;
925 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
926 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
927 ip6_address_t *segments = 0, *this_seg;
932 void *ls_plugin_mem = 0;
934 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
936 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
938 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
940 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
943 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
945 else if (!is_add && !policy_set
946 && unformat (input, "index %d", &sr_policy_index))
948 else if (unformat (input, "weight %d", &weight));
950 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
952 vec_add2 (segments, this_seg, 1);
953 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
956 else if (unformat (input, "add sl"))
958 else if (unformat (input, "del sl index %d", &sl_index))
960 else if (unformat (input, "mod sl index %d", &sl_index))
962 else if (fib_table == (u32) ~ 0
963 && unformat (input, "fib-table %d", &fib_table));
964 else if (unformat (input, "encap"))
966 else if (unformat (input, "insert"))
968 else if (unformat (input, "spray"))
970 else if (!behavior && unformat (input, "behavior"))
972 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
973 sr_policy_fn_registration_t **plugin_it = 0;
976 pool_foreach (plugin, sm->policy_plugin_functions,
978 vec_add1 (vec_plugins, plugin);
982 vec_foreach (plugin_it, vec_plugins)
985 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
987 behavior = (*plugin_it)->sr_policy_function_number;
994 return clib_error_return (0, "Invalid behavior");
1001 if (!is_add && !is_mod && !is_del)
1002 return clib_error_return (0, "Incorrect CLI");
1005 return clib_error_return (0, "No SR policy BSID or index specified");
1009 if (behavior && vec_len (segments) == 0)
1011 vec_add2 (segments, this_seg, 1);
1012 clib_memset (this_seg, 0, sizeof (*this_seg));
1015 if (vec_len (segments) == 0)
1016 return clib_error_return (0, "No Segment List specified");
1018 rv = sr_policy_add (&bsid, segments, weight,
1019 (is_spray ? SR_POLICY_TYPE_SPRAY :
1020 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1021 behavior, ls_plugin_mem);
1023 vec_free (segments);
1026 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1031 return clib_error_return (0, "No SL modification specified");
1032 if (operation != 1 && sl_index == (u32) ~ 0)
1033 return clib_error_return (0, "No Segment List index specified");
1034 if (operation == 1 && vec_len (segments) == 0)
1035 return clib_error_return (0, "No Segment List specified");
1036 if (operation == 3 && weight == (u32) ~ 0)
1037 return clib_error_return (0, "No new weight for the SL specified");
1039 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1040 sr_policy_index, fib_table, operation, segments,
1044 vec_free (segments);
1054 return clib_error_return (0,
1055 "There is already a FIB entry for the BindingSID address.\n"
1056 "The SR policy could not be created.");
1058 return clib_error_return (0, "The specified FIB table does not exist.");
1060 return clib_error_return (0,
1061 "The selected SR policy only contains ONE segment list. "
1062 "Please remove the SR policy instead");
1064 return clib_error_return (0,
1065 "Could not delete the segment list. "
1066 "It is not associated with that SR policy.");
1068 return clib_error_return (0,
1069 "Could not modify the segment list. "
1070 "The given SL is not associated with such SR policy.");
1072 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1078 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1079 .path = "sr policy",
1080 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1081 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1083 "Manipulation of SR policies.\n"
1084 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1085 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1086 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1087 "Each SR policy will be associated with a unique BindingSID.\n"
1088 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1089 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1090 "The add command will create a SR policy with its first segment list (sl)\n"
1091 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1092 "within an SR policy.\n"
1093 "The del command allows you to delete a SR policy along with all its associated\n"
1095 .function = sr_policy_command_fn,
1100 * @brief CLI to display onscreen all the SR policies
1102 static clib_error_t *
1103 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1104 vlib_cli_command_t * cmd)
1106 ip6_sr_main_t *sm = &sr_main;
1108 ip6_sr_sl_t *segment_list = 0;
1109 ip6_sr_policy_t *sr_policy = 0;
1110 ip6_sr_policy_t **vec_policies = 0;
1111 ip6_address_t *addr;
1115 vlib_cli_output (vm, "SR policies:");
1118 pool_foreach (sr_policy, sm->sr_policies,
1119 {vec_add1 (vec_policies, sr_policy); } );
1122 vec_foreach_index (i, vec_policies)
1124 sr_policy = vec_policies[i];
1125 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1126 (u32) (sr_policy - sm->sr_policies),
1127 format_ip6_address, &sr_policy->bsid);
1128 vlib_cli_output (vm, "\tBehavior: %s",
1129 (sr_policy->is_encap ? "Encapsulation" :
1131 vlib_cli_output (vm, "\tType: %s",
1133 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1134 vlib_cli_output (vm, "\tFIB table: %u",
1135 (sr_policy->fib_table !=
1136 (u32) ~ 0 ? sr_policy->fib_table : 0));
1137 vlib_cli_output (vm, "\tSegment Lists:");
1138 vec_foreach (sl_index, sr_policy->segments_lists)
1141 s = format (s, "\t[%u].- ", *sl_index);
1142 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1143 s = format (s, "< ");
1144 vec_foreach (addr, segment_list->segments)
1146 s = format (s, "%U, ", format_ip6_address, addr);
1148 s = format (s, "\b\b > ");
1149 s = format (s, "weight: %u", segment_list->weight);
1150 vlib_cli_output (vm, " %s", s);
1152 vlib_cli_output (vm, "-----------");
1158 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1159 .path = "show sr policies",
1160 .short_help = "show sr policies",
1161 .function = show_sr_policies_command_fn,
1165 /*************************** SR rewrite graph node ****************************/
1167 * @brief Trace for the SR Policy Rewrite graph node
1170 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1173 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1174 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1175 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1178 (s, "SR-policy-rewrite: src %U dst %U",
1179 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1185 * @brief IPv6 encapsulation processing as per RFC2473
1187 static_always_inline void
1188 encaps_processing_v6 (vlib_node_runtime_t * node,
1190 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1194 ip0_encap->hop_limit -= 1;
1196 ip0->payload_length + sizeof (ip6_header_t) +
1197 clib_net_to_host_u16 (ip0_encap->payload_length);
1198 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1199 ip0->ip_version_traffic_class_and_flow_label =
1200 ip0_encap->ip_version_traffic_class_and_flow_label;
1204 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1207 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1208 vlib_frame_t * from_frame)
1210 ip6_sr_main_t *sm = &sr_main;
1211 u32 n_left_from, next_index, *from, *to_next;
1213 from = vlib_frame_vector_args (from_frame);
1214 n_left_from = from_frame->n_vectors;
1216 next_index = node->cached_next_index;
1218 int encap_pkts = 0, bsid_pkts = 0;
1220 while (n_left_from > 0)
1224 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1227 while (n_left_from >= 8 && n_left_to_next >= 4)
1229 u32 bi0, bi1, bi2, bi3;
1230 vlib_buffer_t *b0, *b1, *b2, *b3;
1231 u32 next0, next1, next2, next3;
1232 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1233 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1234 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1235 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1237 /* Prefetch next iteration. */
1239 vlib_buffer_t *p4, *p5, *p6, *p7;
1241 p4 = vlib_get_buffer (vm, from[4]);
1242 p5 = vlib_get_buffer (vm, from[5]);
1243 p6 = vlib_get_buffer (vm, from[6]);
1244 p7 = vlib_get_buffer (vm, from[7]);
1246 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1247 vlib_prefetch_buffer_header (p4, LOAD);
1248 vlib_prefetch_buffer_header (p5, LOAD);
1249 vlib_prefetch_buffer_header (p6, LOAD);
1250 vlib_prefetch_buffer_header (p7, LOAD);
1252 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1253 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1254 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1255 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1258 to_next[0] = bi0 = from[0];
1259 to_next[1] = bi1 = from[1];
1260 to_next[2] = bi2 = from[2];
1261 to_next[3] = bi3 = from[3];
1265 n_left_to_next -= 4;
1267 b0 = vlib_get_buffer (vm, bi0);
1268 b1 = vlib_get_buffer (vm, bi1);
1269 b2 = vlib_get_buffer (vm, bi2);
1270 b3 = vlib_get_buffer (vm, bi3);
1273 pool_elt_at_index (sm->sid_lists,
1274 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1276 pool_elt_at_index (sm->sid_lists,
1277 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1279 pool_elt_at_index (sm->sid_lists,
1280 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1282 pool_elt_at_index (sm->sid_lists,
1283 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1285 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1286 vec_len (sl0->rewrite));
1287 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1288 vec_len (sl1->rewrite));
1289 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1290 vec_len (sl2->rewrite));
1291 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1292 vec_len (sl3->rewrite));
1294 ip0_encap = vlib_buffer_get_current (b0);
1295 ip1_encap = vlib_buffer_get_current (b1);
1296 ip2_encap = vlib_buffer_get_current (b2);
1297 ip3_encap = vlib_buffer_get_current (b3);
1299 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1300 sl0->rewrite, vec_len (sl0->rewrite));
1301 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1302 sl1->rewrite, vec_len (sl1->rewrite));
1303 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1304 sl2->rewrite, vec_len (sl2->rewrite));
1305 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1306 sl3->rewrite, vec_len (sl3->rewrite));
1308 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1309 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1310 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1311 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1313 ip0 = vlib_buffer_get_current (b0);
1314 ip1 = vlib_buffer_get_current (b1);
1315 ip2 = vlib_buffer_get_current (b2);
1316 ip3 = vlib_buffer_get_current (b3);
1318 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1319 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1320 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1321 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1323 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1325 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1327 sr_policy_rewrite_trace_t *tr =
1328 vlib_add_trace (vm, node, b0, sizeof (*tr));
1329 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1330 sizeof (tr->src.as_u8));
1331 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1332 sizeof (tr->dst.as_u8));
1335 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1337 sr_policy_rewrite_trace_t *tr =
1338 vlib_add_trace (vm, node, b1, sizeof (*tr));
1339 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1340 sizeof (tr->src.as_u8));
1341 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1342 sizeof (tr->dst.as_u8));
1345 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1347 sr_policy_rewrite_trace_t *tr =
1348 vlib_add_trace (vm, node, b2, sizeof (*tr));
1349 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1350 sizeof (tr->src.as_u8));
1351 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1352 sizeof (tr->dst.as_u8));
1355 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1357 sr_policy_rewrite_trace_t *tr =
1358 vlib_add_trace (vm, node, b3, sizeof (*tr));
1359 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1360 sizeof (tr->src.as_u8));
1361 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1362 sizeof (tr->dst.as_u8));
1367 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1368 n_left_to_next, bi0, bi1, bi2, bi3,
1369 next0, next1, next2, next3);
1372 /* Single loop for potentially the last three packets */
1373 while (n_left_from > 0 && n_left_to_next > 0)
1377 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1379 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1386 n_left_to_next -= 1;
1387 b0 = vlib_get_buffer (vm, bi0);
1390 pool_elt_at_index (sm->sid_lists,
1391 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1392 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1393 vec_len (sl0->rewrite));
1395 ip0_encap = vlib_buffer_get_current (b0);
1397 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1398 sl0->rewrite, vec_len (sl0->rewrite));
1399 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1401 ip0 = vlib_buffer_get_current (b0);
1403 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1405 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1406 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1408 sr_policy_rewrite_trace_t *tr =
1409 vlib_add_trace (vm, node, b0, sizeof (*tr));
1410 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1411 sizeof (tr->src.as_u8));
1412 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1413 sizeof (tr->dst.as_u8));
1417 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1418 n_left_to_next, bi0, next0);
1421 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1424 /* Update counters */
1425 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1426 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1428 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1429 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1432 return from_frame->n_vectors;
1436 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1437 .function = sr_policy_rewrite_encaps,
1438 .name = "sr-pl-rewrite-encaps",
1439 .vector_size = sizeof (u32),
1440 .format_trace = format_sr_policy_rewrite_trace,
1441 .type = VLIB_NODE_TYPE_INTERNAL,
1442 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1443 .error_strings = sr_policy_rewrite_error_strings,
1444 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1446 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1447 foreach_sr_policy_rewrite_next
1454 * @brief IPv4 encapsulation processing as per RFC2473
1456 static_always_inline void
1457 encaps_processing_v4 (vlib_node_runtime_t * node,
1459 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1462 ip6_sr_header_t *sr0;
1466 /* Inner IPv4: Decrement TTL & update checksum */
1467 ip0_encap->ttl -= 1;
1468 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1469 checksum0 += checksum0 >= 0xffff;
1470 ip0_encap->checksum = checksum0;
1472 /* Outer IPv6: Update length, FL, proto */
1473 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1474 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1475 ip0->ip_version_traffic_class_and_flow_label =
1476 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1477 ((ip0_encap->tos & 0xFF) << 20));
1478 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1480 sr0 = (void *) (ip0 + 1);
1481 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1484 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1488 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1491 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1492 vlib_frame_t * from_frame)
1494 ip6_sr_main_t *sm = &sr_main;
1495 u32 n_left_from, next_index, *from, *to_next;
1497 from = vlib_frame_vector_args (from_frame);
1498 n_left_from = from_frame->n_vectors;
1500 next_index = node->cached_next_index;
1502 int encap_pkts = 0, bsid_pkts = 0;
1504 while (n_left_from > 0)
1508 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1511 while (n_left_from >= 8 && n_left_to_next >= 4)
1513 u32 bi0, bi1, bi2, bi3;
1514 vlib_buffer_t *b0, *b1, *b2, *b3;
1515 u32 next0, next1, next2, next3;
1516 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1517 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1518 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1519 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1521 /* Prefetch next iteration. */
1523 vlib_buffer_t *p4, *p5, *p6, *p7;
1525 p4 = vlib_get_buffer (vm, from[4]);
1526 p5 = vlib_get_buffer (vm, from[5]);
1527 p6 = vlib_get_buffer (vm, from[6]);
1528 p7 = vlib_get_buffer (vm, from[7]);
1530 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1531 vlib_prefetch_buffer_header (p4, LOAD);
1532 vlib_prefetch_buffer_header (p5, LOAD);
1533 vlib_prefetch_buffer_header (p6, LOAD);
1534 vlib_prefetch_buffer_header (p7, LOAD);
1536 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1537 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1538 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1539 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1542 to_next[0] = bi0 = from[0];
1543 to_next[1] = bi1 = from[1];
1544 to_next[2] = bi2 = from[2];
1545 to_next[3] = bi3 = from[3];
1549 n_left_to_next -= 4;
1551 b0 = vlib_get_buffer (vm, bi0);
1552 b1 = vlib_get_buffer (vm, bi1);
1553 b2 = vlib_get_buffer (vm, bi2);
1554 b3 = vlib_get_buffer (vm, bi3);
1557 pool_elt_at_index (sm->sid_lists,
1558 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1560 pool_elt_at_index (sm->sid_lists,
1561 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1563 pool_elt_at_index (sm->sid_lists,
1564 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1566 pool_elt_at_index (sm->sid_lists,
1567 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1568 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1569 vec_len (sl0->rewrite));
1570 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1571 vec_len (sl1->rewrite));
1572 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1573 vec_len (sl2->rewrite));
1574 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1575 vec_len (sl3->rewrite));
1577 ip0_encap = vlib_buffer_get_current (b0);
1578 ip1_encap = vlib_buffer_get_current (b1);
1579 ip2_encap = vlib_buffer_get_current (b2);
1580 ip3_encap = vlib_buffer_get_current (b3);
1582 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1583 sl0->rewrite, vec_len (sl0->rewrite));
1584 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1585 sl1->rewrite, vec_len (sl1->rewrite));
1586 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1587 sl2->rewrite, vec_len (sl2->rewrite));
1588 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1589 sl3->rewrite, vec_len (sl3->rewrite));
1591 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1592 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1593 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1594 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1596 ip0 = vlib_buffer_get_current (b0);
1597 ip1 = vlib_buffer_get_current (b1);
1598 ip2 = vlib_buffer_get_current (b2);
1599 ip3 = vlib_buffer_get_current (b3);
1601 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1602 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1603 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1604 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1606 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1608 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1610 sr_policy_rewrite_trace_t *tr =
1611 vlib_add_trace (vm, node, b0, sizeof (*tr));
1612 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1613 sizeof (tr->src.as_u8));
1614 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1615 sizeof (tr->dst.as_u8));
1618 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1620 sr_policy_rewrite_trace_t *tr =
1621 vlib_add_trace (vm, node, b1, sizeof (*tr));
1622 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1623 sizeof (tr->src.as_u8));
1624 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1625 sizeof (tr->dst.as_u8));
1628 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1630 sr_policy_rewrite_trace_t *tr =
1631 vlib_add_trace (vm, node, b2, sizeof (*tr));
1632 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1633 sizeof (tr->src.as_u8));
1634 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1635 sizeof (tr->dst.as_u8));
1638 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1640 sr_policy_rewrite_trace_t *tr =
1641 vlib_add_trace (vm, node, b3, sizeof (*tr));
1642 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1643 sizeof (tr->src.as_u8));
1644 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1645 sizeof (tr->dst.as_u8));
1650 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1651 n_left_to_next, bi0, bi1, bi2, bi3,
1652 next0, next1, next2, next3);
1655 /* Single loop for potentially the last three packets */
1656 while (n_left_from > 0 && n_left_to_next > 0)
1660 ip6_header_t *ip0 = 0;
1661 ip4_header_t *ip0_encap = 0;
1663 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1670 n_left_to_next -= 1;
1671 b0 = vlib_get_buffer (vm, bi0);
1674 pool_elt_at_index (sm->sid_lists,
1675 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1676 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1677 vec_len (sl0->rewrite));
1679 ip0_encap = vlib_buffer_get_current (b0);
1681 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1682 sl0->rewrite, vec_len (sl0->rewrite));
1683 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1685 ip0 = vlib_buffer_get_current (b0);
1687 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1689 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1690 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1692 sr_policy_rewrite_trace_t *tr =
1693 vlib_add_trace (vm, node, b0, sizeof (*tr));
1694 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1695 sizeof (tr->src.as_u8));
1696 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1697 sizeof (tr->dst.as_u8));
1701 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1702 n_left_to_next, bi0, next0);
1705 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1708 /* Update counters */
1709 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1710 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1712 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1713 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1716 return from_frame->n_vectors;
1720 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1721 .function = sr_policy_rewrite_encaps_v4,
1722 .name = "sr-pl-rewrite-encaps-v4",
1723 .vector_size = sizeof (u32),
1724 .format_trace = format_sr_policy_rewrite_trace,
1725 .type = VLIB_NODE_TYPE_INTERNAL,
1726 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1727 .error_strings = sr_policy_rewrite_error_strings,
1728 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1730 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1731 foreach_sr_policy_rewrite_next
1738 ip_flow_hash (void *data)
1740 ip4_header_t *iph = (ip4_header_t *) data;
1742 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1743 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1745 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1751 return (*((u64 *) m) & 0xffffffffffff);
1755 l2_flow_hash (vlib_buffer_t * b0)
1757 ethernet_header_t *eh;
1759 uword is_ip, eh_size;
1762 eh = vlib_buffer_get_current (b0);
1763 eh_type = clib_net_to_host_u16 (eh->type);
1764 eh_size = ethernet_buffer_header_size (b0);
1766 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1768 /* since we have 2 cache lines, use them */
1770 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1774 b = mac_to_u64 ((u8 *) eh->dst_address);
1775 c = mac_to_u64 ((u8 *) eh->src_address);
1776 hash_mix64 (a, b, c);
1782 * @brief Graph node for applying a SR policy into a L2 frame
1785 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1786 vlib_frame_t * from_frame)
1788 ip6_sr_main_t *sm = &sr_main;
1789 u32 n_left_from, next_index, *from, *to_next;
1791 from = vlib_frame_vector_args (from_frame);
1792 n_left_from = from_frame->n_vectors;
1794 next_index = node->cached_next_index;
1796 int encap_pkts = 0, bsid_pkts = 0;
1798 while (n_left_from > 0)
1802 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1805 while (n_left_from >= 8 && n_left_to_next >= 4)
1807 u32 bi0, bi1, bi2, bi3;
1808 vlib_buffer_t *b0, *b1, *b2, *b3;
1809 u32 next0, next1, next2, next3;
1810 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1811 ethernet_header_t *en0, *en1, *en2, *en3;
1812 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1813 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1814 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1815 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1817 /* Prefetch next iteration. */
1819 vlib_buffer_t *p4, *p5, *p6, *p7;
1821 p4 = vlib_get_buffer (vm, from[4]);
1822 p5 = vlib_get_buffer (vm, from[5]);
1823 p6 = vlib_get_buffer (vm, from[6]);
1824 p7 = vlib_get_buffer (vm, from[7]);
1826 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1827 vlib_prefetch_buffer_header (p4, LOAD);
1828 vlib_prefetch_buffer_header (p5, LOAD);
1829 vlib_prefetch_buffer_header (p6, LOAD);
1830 vlib_prefetch_buffer_header (p7, LOAD);
1832 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1833 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1834 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1835 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1838 to_next[0] = bi0 = from[0];
1839 to_next[1] = bi1 = from[1];
1840 to_next[2] = bi2 = from[2];
1841 to_next[3] = bi3 = from[3];
1845 n_left_to_next -= 4;
1847 b0 = vlib_get_buffer (vm, bi0);
1848 b1 = vlib_get_buffer (vm, bi1);
1849 b2 = vlib_get_buffer (vm, bi2);
1850 b3 = vlib_get_buffer (vm, bi3);
1852 sp0 = pool_elt_at_index (sm->sr_policies,
1853 sm->sw_iface_sr_policies[vnet_buffer
1857 sp1 = pool_elt_at_index (sm->sr_policies,
1858 sm->sw_iface_sr_policies[vnet_buffer
1862 sp2 = pool_elt_at_index (sm->sr_policies,
1863 sm->sw_iface_sr_policies[vnet_buffer
1867 sp3 = pool_elt_at_index (sm->sr_policies,
1868 sm->sw_iface_sr_policies[vnet_buffer
1872 if (vec_len (sp0->segments_lists) == 1)
1873 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1876 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1877 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1878 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1879 (vec_len (sp0->segments_lists) - 1))];
1882 if (vec_len (sp1->segments_lists) == 1)
1883 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1886 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1887 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1888 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1889 (vec_len (sp1->segments_lists) - 1))];
1892 if (vec_len (sp2->segments_lists) == 1)
1893 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1896 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1897 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1898 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1899 (vec_len (sp2->segments_lists) - 1))];
1902 if (vec_len (sp3->segments_lists) == 1)
1903 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1906 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1907 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1908 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1909 (vec_len (sp3->segments_lists) - 1))];
1913 pool_elt_at_index (sm->sid_lists,
1914 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1916 pool_elt_at_index (sm->sid_lists,
1917 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1919 pool_elt_at_index (sm->sid_lists,
1920 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1922 pool_elt_at_index (sm->sid_lists,
1923 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1925 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1926 vec_len (sl0->rewrite));
1927 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1928 vec_len (sl1->rewrite));
1929 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1930 vec_len (sl2->rewrite));
1931 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1932 vec_len (sl3->rewrite));
1934 en0 = vlib_buffer_get_current (b0);
1935 en1 = vlib_buffer_get_current (b1);
1936 en2 = vlib_buffer_get_current (b2);
1937 en3 = vlib_buffer_get_current (b3);
1939 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
1940 sl0->rewrite, vec_len (sl0->rewrite));
1941 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
1942 sl1->rewrite, vec_len (sl1->rewrite));
1943 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
1944 sl2->rewrite, vec_len (sl2->rewrite));
1945 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
1946 sl3->rewrite, vec_len (sl3->rewrite));
1948 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1949 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1950 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1951 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1953 ip0 = vlib_buffer_get_current (b0);
1954 ip1 = vlib_buffer_get_current (b1);
1955 ip2 = vlib_buffer_get_current (b2);
1956 ip3 = vlib_buffer_get_current (b3);
1958 ip0->payload_length =
1959 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1960 ip1->payload_length =
1961 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1962 ip2->payload_length =
1963 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1964 ip3->payload_length =
1965 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1967 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1969 sr0 = (void *) (ip0 + 1);
1970 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
1973 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
1975 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1977 sr1 = (void *) (ip1 + 1);
1978 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
1981 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
1983 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1985 sr2 = (void *) (ip2 + 1);
1986 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
1989 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
1991 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1993 sr3 = (void *) (ip3 + 1);
1994 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
1997 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
1999 /* Which Traffic class and flow label do I set ? */
2000 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
2002 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2004 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2006 sr_policy_rewrite_trace_t *tr =
2007 vlib_add_trace (vm, node, b0, sizeof (*tr));
2008 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2009 sizeof (tr->src.as_u8));
2010 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2011 sizeof (tr->dst.as_u8));
2014 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2016 sr_policy_rewrite_trace_t *tr =
2017 vlib_add_trace (vm, node, b1, sizeof (*tr));
2018 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2019 sizeof (tr->src.as_u8));
2020 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2021 sizeof (tr->dst.as_u8));
2024 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2026 sr_policy_rewrite_trace_t *tr =
2027 vlib_add_trace (vm, node, b2, sizeof (*tr));
2028 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2029 sizeof (tr->src.as_u8));
2030 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2031 sizeof (tr->dst.as_u8));
2034 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2036 sr_policy_rewrite_trace_t *tr =
2037 vlib_add_trace (vm, node, b3, sizeof (*tr));
2038 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2039 sizeof (tr->src.as_u8));
2040 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2041 sizeof (tr->dst.as_u8));
2046 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2047 n_left_to_next, bi0, bi1, bi2, bi3,
2048 next0, next1, next2, next3);
2051 /* Single loop for potentially the last three packets */
2052 while (n_left_from > 0 && n_left_to_next > 0)
2056 ip6_header_t *ip0 = 0;
2057 ip6_sr_header_t *sr0;
2058 ethernet_header_t *en0;
2059 ip6_sr_policy_t *sp0;
2061 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2068 n_left_to_next -= 1;
2069 b0 = vlib_get_buffer (vm, bi0);
2071 /* Find the SR policy */
2072 sp0 = pool_elt_at_index (sm->sr_policies,
2073 sm->sw_iface_sr_policies[vnet_buffer
2077 /* In case there is more than one SL, LB among them */
2078 if (vec_len (sp0->segments_lists) == 1)
2079 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2082 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
2083 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2084 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2085 (vec_len (sp0->segments_lists) - 1))];
2088 pool_elt_at_index (sm->sid_lists,
2089 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2090 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2091 vec_len (sl0->rewrite));
2093 en0 = vlib_buffer_get_current (b0);
2095 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2096 sl0->rewrite, vec_len (sl0->rewrite));
2098 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2100 ip0 = vlib_buffer_get_current (b0);
2102 ip0->payload_length =
2103 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2105 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2107 sr0 = (void *) (ip0 + 1);
2108 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2111 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2113 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2114 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2116 sr_policy_rewrite_trace_t *tr =
2117 vlib_add_trace (vm, node, b0, sizeof (*tr));
2118 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2119 sizeof (tr->src.as_u8));
2120 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2121 sizeof (tr->dst.as_u8));
2125 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2126 n_left_to_next, bi0, next0);
2129 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2132 /* Update counters */
2133 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2134 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2136 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2137 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2140 return from_frame->n_vectors;
2144 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2145 .function = sr_policy_rewrite_encaps_l2,
2146 .name = "sr-pl-rewrite-encaps-l2",
2147 .vector_size = sizeof (u32),
2148 .format_trace = format_sr_policy_rewrite_trace,
2149 .type = VLIB_NODE_TYPE_INTERNAL,
2150 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2151 .error_strings = sr_policy_rewrite_error_strings,
2152 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2154 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2155 foreach_sr_policy_rewrite_next
2162 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2165 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2166 vlib_frame_t * from_frame)
2168 ip6_sr_main_t *sm = &sr_main;
2169 u32 n_left_from, next_index, *from, *to_next;
2171 from = vlib_frame_vector_args (from_frame);
2172 n_left_from = from_frame->n_vectors;
2174 next_index = node->cached_next_index;
2176 int insert_pkts = 0, bsid_pkts = 0;
2178 while (n_left_from > 0)
2182 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2185 while (n_left_from >= 8 && n_left_to_next >= 4)
2187 u32 bi0, bi1, bi2, bi3;
2188 vlib_buffer_t *b0, *b1, *b2, *b3;
2189 u32 next0, next1, next2, next3;
2190 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2191 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2192 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2193 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2194 u16 new_l0, new_l1, new_l2, new_l3;
2196 /* Prefetch next iteration. */
2198 vlib_buffer_t *p4, *p5, *p6, *p7;
2200 p4 = vlib_get_buffer (vm, from[4]);
2201 p5 = vlib_get_buffer (vm, from[5]);
2202 p6 = vlib_get_buffer (vm, from[6]);
2203 p7 = vlib_get_buffer (vm, from[7]);
2205 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2206 vlib_prefetch_buffer_header (p4, LOAD);
2207 vlib_prefetch_buffer_header (p5, LOAD);
2208 vlib_prefetch_buffer_header (p6, LOAD);
2209 vlib_prefetch_buffer_header (p7, LOAD);
2211 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2212 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2213 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2214 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2217 to_next[0] = bi0 = from[0];
2218 to_next[1] = bi1 = from[1];
2219 to_next[2] = bi2 = from[2];
2220 to_next[3] = bi3 = from[3];
2224 n_left_to_next -= 4;
2226 b0 = vlib_get_buffer (vm, bi0);
2227 b1 = vlib_get_buffer (vm, bi1);
2228 b2 = vlib_get_buffer (vm, bi2);
2229 b3 = vlib_get_buffer (vm, bi3);
2232 pool_elt_at_index (sm->sid_lists,
2233 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2235 pool_elt_at_index (sm->sid_lists,
2236 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2238 pool_elt_at_index (sm->sid_lists,
2239 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2241 pool_elt_at_index (sm->sid_lists,
2242 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2244 vec_len (sl0->rewrite));
2245 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2246 vec_len (sl1->rewrite));
2247 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2248 vec_len (sl2->rewrite));
2249 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2250 vec_len (sl3->rewrite));
2252 ip0 = vlib_buffer_get_current (b0);
2253 ip1 = vlib_buffer_get_current (b1);
2254 ip2 = vlib_buffer_get_current (b2);
2255 ip3 = vlib_buffer_get_current (b3);
2257 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2259 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2260 ip6_ext_header_len (ip0 + 1));
2262 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2264 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2266 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2267 ip6_ext_header_len (ip1 + 1));
2269 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2271 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2273 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2274 ip6_ext_header_len (ip2 + 1));
2276 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2278 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2280 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2281 ip6_ext_header_len (ip3 + 1));
2283 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2285 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2286 (void *) sr0 - (void *) ip0);
2287 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2288 (void *) sr1 - (void *) ip1);
2289 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2290 (void *) sr2 - (void *) ip2);
2291 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2292 (void *) sr3 - (void *) ip3);
2294 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2295 sl0->rewrite, vec_len (sl0->rewrite));
2296 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2297 sl1->rewrite, vec_len (sl1->rewrite));
2298 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2299 sl2->rewrite, vec_len (sl2->rewrite));
2300 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2301 sl3->rewrite, vec_len (sl3->rewrite));
2303 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2304 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2305 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2306 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2308 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2309 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2310 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2311 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2313 ip0->hop_limit -= 1;
2314 ip1->hop_limit -= 1;
2315 ip2->hop_limit -= 1;
2316 ip3->hop_limit -= 1;
2319 clib_net_to_host_u16 (ip0->payload_length) +
2320 vec_len (sl0->rewrite);
2322 clib_net_to_host_u16 (ip1->payload_length) +
2323 vec_len (sl1->rewrite);
2325 clib_net_to_host_u16 (ip2->payload_length) +
2326 vec_len (sl2->rewrite);
2328 clib_net_to_host_u16 (ip3->payload_length) +
2329 vec_len (sl3->rewrite);
2331 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2332 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2333 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2334 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2336 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2337 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2338 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2339 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2341 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2342 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2343 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2344 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2345 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2346 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2347 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2348 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2350 ip0->dst_address.as_u64[0] =
2351 (sr0->segments + sr0->segments_left)->as_u64[0];
2352 ip0->dst_address.as_u64[1] =
2353 (sr0->segments + sr0->segments_left)->as_u64[1];
2354 ip1->dst_address.as_u64[0] =
2355 (sr1->segments + sr1->segments_left)->as_u64[0];
2356 ip1->dst_address.as_u64[1] =
2357 (sr1->segments + sr1->segments_left)->as_u64[1];
2358 ip2->dst_address.as_u64[0] =
2359 (sr2->segments + sr2->segments_left)->as_u64[0];
2360 ip2->dst_address.as_u64[1] =
2361 (sr2->segments + sr2->segments_left)->as_u64[1];
2362 ip3->dst_address.as_u64[0] =
2363 (sr3->segments + sr3->segments_left)->as_u64[0];
2364 ip3->dst_address.as_u64[1] =
2365 (sr3->segments + sr3->segments_left)->as_u64[1];
2367 ip6_ext_header_t *ip_ext;
2368 if (ip0 + 1 == (void *) sr0)
2370 sr0->protocol = ip0->protocol;
2371 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2375 ip_ext = (void *) (ip0 + 1);
2376 sr0->protocol = ip_ext->next_hdr;
2377 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2380 if (ip1 + 1 == (void *) sr1)
2382 sr1->protocol = ip1->protocol;
2383 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2387 ip_ext = (void *) (ip2 + 1);
2388 sr2->protocol = ip_ext->next_hdr;
2389 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2392 if (ip2 + 1 == (void *) sr2)
2394 sr2->protocol = ip2->protocol;
2395 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2399 ip_ext = (void *) (ip2 + 1);
2400 sr2->protocol = ip_ext->next_hdr;
2401 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2404 if (ip3 + 1 == (void *) sr3)
2406 sr3->protocol = ip3->protocol;
2407 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2411 ip_ext = (void *) (ip3 + 1);
2412 sr3->protocol = ip_ext->next_hdr;
2413 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2418 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2420 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2422 sr_policy_rewrite_trace_t *tr =
2423 vlib_add_trace (vm, node, b0, sizeof (*tr));
2424 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2425 sizeof (tr->src.as_u8));
2426 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2427 sizeof (tr->dst.as_u8));
2430 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2432 sr_policy_rewrite_trace_t *tr =
2433 vlib_add_trace (vm, node, b1, sizeof (*tr));
2434 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2435 sizeof (tr->src.as_u8));
2436 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2437 sizeof (tr->dst.as_u8));
2440 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2442 sr_policy_rewrite_trace_t *tr =
2443 vlib_add_trace (vm, node, b2, sizeof (*tr));
2444 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2445 sizeof (tr->src.as_u8));
2446 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2447 sizeof (tr->dst.as_u8));
2450 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2452 sr_policy_rewrite_trace_t *tr =
2453 vlib_add_trace (vm, node, b3, sizeof (*tr));
2454 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2455 sizeof (tr->src.as_u8));
2456 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2457 sizeof (tr->dst.as_u8));
2461 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2462 n_left_to_next, bi0, bi1, bi2, bi3,
2463 next0, next1, next2, next3);
2466 /* Single loop for potentially the last three packets */
2467 while (n_left_from > 0 && n_left_to_next > 0)
2471 ip6_header_t *ip0 = 0;
2472 ip6_sr_header_t *sr0 = 0;
2474 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2482 n_left_to_next -= 1;
2484 b0 = vlib_get_buffer (vm, bi0);
2486 pool_elt_at_index (sm->sid_lists,
2487 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2488 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2489 vec_len (sl0->rewrite));
2491 ip0 = vlib_buffer_get_current (b0);
2493 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2495 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2496 ip6_ext_header_len (ip0 + 1));
2498 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2500 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2501 (void *) sr0 - (void *) ip0);
2502 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2503 sl0->rewrite, vec_len (sl0->rewrite));
2505 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2507 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2508 ip0->hop_limit -= 1;
2510 clib_net_to_host_u16 (ip0->payload_length) +
2511 vec_len (sl0->rewrite);
2512 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2514 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2515 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2516 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2518 ip0->dst_address.as_u64[0] =
2519 (sr0->segments + sr0->segments_left)->as_u64[0];
2520 ip0->dst_address.as_u64[1] =
2521 (sr0->segments + sr0->segments_left)->as_u64[1];
2523 if (ip0 + 1 == (void *) sr0)
2525 sr0->protocol = ip0->protocol;
2526 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2530 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2531 sr0->protocol = ip_ext->next_hdr;
2532 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2535 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2536 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2538 sr_policy_rewrite_trace_t *tr =
2539 vlib_add_trace (vm, node, b0, sizeof (*tr));
2540 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2541 sizeof (tr->src.as_u8));
2542 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2543 sizeof (tr->dst.as_u8));
2548 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2549 n_left_to_next, bi0, next0);
2552 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2555 /* Update counters */
2556 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2557 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2559 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2560 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2562 return from_frame->n_vectors;
2566 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2567 .function = sr_policy_rewrite_insert,
2568 .name = "sr-pl-rewrite-insert",
2569 .vector_size = sizeof (u32),
2570 .format_trace = format_sr_policy_rewrite_trace,
2571 .type = VLIB_NODE_TYPE_INTERNAL,
2572 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2573 .error_strings = sr_policy_rewrite_error_strings,
2574 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2576 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2577 foreach_sr_policy_rewrite_next
2584 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2587 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2588 vlib_frame_t * from_frame)
2590 ip6_sr_main_t *sm = &sr_main;
2591 u32 n_left_from, next_index, *from, *to_next;
2593 from = vlib_frame_vector_args (from_frame);
2594 n_left_from = from_frame->n_vectors;
2596 next_index = node->cached_next_index;
2598 int insert_pkts = 0, bsid_pkts = 0;
2600 while (n_left_from > 0)
2604 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2607 while (n_left_from >= 8 && n_left_to_next >= 4)
2609 u32 bi0, bi1, bi2, bi3;
2610 vlib_buffer_t *b0, *b1, *b2, *b3;
2611 u32 next0, next1, next2, next3;
2612 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2613 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2614 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2615 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2616 u16 new_l0, new_l1, new_l2, new_l3;
2618 /* Prefetch next iteration. */
2620 vlib_buffer_t *p4, *p5, *p6, *p7;
2622 p4 = vlib_get_buffer (vm, from[4]);
2623 p5 = vlib_get_buffer (vm, from[5]);
2624 p6 = vlib_get_buffer (vm, from[6]);
2625 p7 = vlib_get_buffer (vm, from[7]);
2627 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2628 vlib_prefetch_buffer_header (p4, LOAD);
2629 vlib_prefetch_buffer_header (p5, LOAD);
2630 vlib_prefetch_buffer_header (p6, LOAD);
2631 vlib_prefetch_buffer_header (p7, LOAD);
2633 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2634 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2635 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2636 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2639 to_next[0] = bi0 = from[0];
2640 to_next[1] = bi1 = from[1];
2641 to_next[2] = bi2 = from[2];
2642 to_next[3] = bi3 = from[3];
2646 n_left_to_next -= 4;
2648 b0 = vlib_get_buffer (vm, bi0);
2649 b1 = vlib_get_buffer (vm, bi1);
2650 b2 = vlib_get_buffer (vm, bi2);
2651 b3 = vlib_get_buffer (vm, bi3);
2654 pool_elt_at_index (sm->sid_lists,
2655 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2657 pool_elt_at_index (sm->sid_lists,
2658 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2660 pool_elt_at_index (sm->sid_lists,
2661 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2663 pool_elt_at_index (sm->sid_lists,
2664 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2665 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2666 vec_len (sl0->rewrite_bsid));
2667 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2668 vec_len (sl1->rewrite_bsid));
2669 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2670 vec_len (sl2->rewrite_bsid));
2671 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2672 vec_len (sl3->rewrite_bsid));
2674 ip0 = vlib_buffer_get_current (b0);
2675 ip1 = vlib_buffer_get_current (b1);
2676 ip2 = vlib_buffer_get_current (b2);
2677 ip3 = vlib_buffer_get_current (b3);
2679 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2681 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2682 ip6_ext_header_len (ip0 + 1));
2684 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2686 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2688 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2689 ip6_ext_header_len (ip1 + 1));
2691 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2693 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2695 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2696 ip6_ext_header_len (ip2 + 1));
2698 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2700 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2702 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2703 ip6_ext_header_len (ip3 + 1));
2705 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2707 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2708 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2709 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2710 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2711 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2712 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2713 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2714 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2716 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2717 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2718 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2719 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2720 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2721 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2722 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2723 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2725 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2726 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2727 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2728 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2730 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2731 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2732 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2733 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2735 ip0->hop_limit -= 1;
2736 ip1->hop_limit -= 1;
2737 ip2->hop_limit -= 1;
2738 ip3->hop_limit -= 1;
2741 clib_net_to_host_u16 (ip0->payload_length) +
2742 vec_len (sl0->rewrite_bsid);
2744 clib_net_to_host_u16 (ip1->payload_length) +
2745 vec_len (sl1->rewrite_bsid);
2747 clib_net_to_host_u16 (ip2->payload_length) +
2748 vec_len (sl2->rewrite_bsid);
2750 clib_net_to_host_u16 (ip3->payload_length) +
2751 vec_len (sl3->rewrite_bsid);
2753 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2754 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2755 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2756 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2758 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2759 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2760 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2761 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2763 ip0->dst_address.as_u64[0] =
2764 (sr0->segments + sr0->segments_left)->as_u64[0];
2765 ip0->dst_address.as_u64[1] =
2766 (sr0->segments + sr0->segments_left)->as_u64[1];
2767 ip1->dst_address.as_u64[0] =
2768 (sr1->segments + sr1->segments_left)->as_u64[0];
2769 ip1->dst_address.as_u64[1] =
2770 (sr1->segments + sr1->segments_left)->as_u64[1];
2771 ip2->dst_address.as_u64[0] =
2772 (sr2->segments + sr2->segments_left)->as_u64[0];
2773 ip2->dst_address.as_u64[1] =
2774 (sr2->segments + sr2->segments_left)->as_u64[1];
2775 ip3->dst_address.as_u64[0] =
2776 (sr3->segments + sr3->segments_left)->as_u64[0];
2777 ip3->dst_address.as_u64[1] =
2778 (sr3->segments + sr3->segments_left)->as_u64[1];
2780 ip6_ext_header_t *ip_ext;
2781 if (ip0 + 1 == (void *) sr0)
2783 sr0->protocol = ip0->protocol;
2784 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2788 ip_ext = (void *) (ip0 + 1);
2789 sr0->protocol = ip_ext->next_hdr;
2790 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2793 if (ip1 + 1 == (void *) sr1)
2795 sr1->protocol = ip1->protocol;
2796 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2800 ip_ext = (void *) (ip2 + 1);
2801 sr2->protocol = ip_ext->next_hdr;
2802 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2805 if (ip2 + 1 == (void *) sr2)
2807 sr2->protocol = ip2->protocol;
2808 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2812 ip_ext = (void *) (ip2 + 1);
2813 sr2->protocol = ip_ext->next_hdr;
2814 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2817 if (ip3 + 1 == (void *) sr3)
2819 sr3->protocol = ip3->protocol;
2820 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2824 ip_ext = (void *) (ip3 + 1);
2825 sr3->protocol = ip_ext->next_hdr;
2826 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2831 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2833 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2835 sr_policy_rewrite_trace_t *tr =
2836 vlib_add_trace (vm, node, b0, sizeof (*tr));
2837 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2838 sizeof (tr->src.as_u8));
2839 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2840 sizeof (tr->dst.as_u8));
2843 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2845 sr_policy_rewrite_trace_t *tr =
2846 vlib_add_trace (vm, node, b1, sizeof (*tr));
2847 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2848 sizeof (tr->src.as_u8));
2849 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2850 sizeof (tr->dst.as_u8));
2853 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2855 sr_policy_rewrite_trace_t *tr =
2856 vlib_add_trace (vm, node, b2, sizeof (*tr));
2857 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2858 sizeof (tr->src.as_u8));
2859 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2860 sizeof (tr->dst.as_u8));
2863 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2865 sr_policy_rewrite_trace_t *tr =
2866 vlib_add_trace (vm, node, b3, sizeof (*tr));
2867 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2868 sizeof (tr->src.as_u8));
2869 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2870 sizeof (tr->dst.as_u8));
2874 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2875 n_left_to_next, bi0, bi1, bi2, bi3,
2876 next0, next1, next2, next3);
2879 /* Single loop for potentially the last three packets */
2880 while (n_left_from > 0 && n_left_to_next > 0)
2884 ip6_header_t *ip0 = 0;
2885 ip6_sr_header_t *sr0 = 0;
2887 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2895 n_left_to_next -= 1;
2897 b0 = vlib_get_buffer (vm, bi0);
2899 pool_elt_at_index (sm->sid_lists,
2900 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2901 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2902 vec_len (sl0->rewrite_bsid));
2904 ip0 = vlib_buffer_get_current (b0);
2906 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2908 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2909 ip6_ext_header_len (ip0 + 1));
2911 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2913 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2914 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2915 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2916 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2918 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2920 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2921 ip0->hop_limit -= 1;
2923 clib_net_to_host_u16 (ip0->payload_length) +
2924 vec_len (sl0->rewrite_bsid);
2925 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2927 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2929 ip0->dst_address.as_u64[0] =
2930 (sr0->segments + sr0->segments_left)->as_u64[0];
2931 ip0->dst_address.as_u64[1] =
2932 (sr0->segments + sr0->segments_left)->as_u64[1];
2934 if (ip0 + 1 == (void *) sr0)
2936 sr0->protocol = ip0->protocol;
2937 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2941 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2942 sr0->protocol = ip_ext->next_hdr;
2943 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2946 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2947 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2949 sr_policy_rewrite_trace_t *tr =
2950 vlib_add_trace (vm, node, b0, sizeof (*tr));
2951 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2952 sizeof (tr->src.as_u8));
2953 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2954 sizeof (tr->dst.as_u8));
2959 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2960 n_left_to_next, bi0, next0);
2963 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2966 /* Update counters */
2967 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2968 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2970 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2971 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2973 return from_frame->n_vectors;
2977 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2978 .function = sr_policy_rewrite_b_insert,
2979 .name = "sr-pl-rewrite-b-insert",
2980 .vector_size = sizeof (u32),
2981 .format_trace = format_sr_policy_rewrite_trace,
2982 .type = VLIB_NODE_TYPE_INTERNAL,
2983 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2984 .error_strings = sr_policy_rewrite_error_strings,
2985 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2987 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2988 foreach_sr_policy_rewrite_next
2995 * @brief Function BSID encapsulation
2997 static_always_inline void
2998 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3001 ip6_sr_header_t * sr0, u32 * next0)
3003 ip6_address_t *new_dst0;
3005 if (PREDICT_FALSE (!sr0))
3006 goto error_bsid_encaps;
3008 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3010 if (PREDICT_TRUE (sr0->segments_left != 0))
3012 sr0->segments_left -= 1;
3013 new_dst0 = (ip6_address_t *) (sr0->segments);
3014 new_dst0 += sr0->segments_left;
3015 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3016 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3022 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3023 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3027 * @brief Graph node for applying a SR policy BSID - Encapsulation
3030 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3031 vlib_frame_t * from_frame)
3033 ip6_sr_main_t *sm = &sr_main;
3034 u32 n_left_from, next_index, *from, *to_next;
3036 from = vlib_frame_vector_args (from_frame);
3037 n_left_from = from_frame->n_vectors;
3039 next_index = node->cached_next_index;
3041 int encap_pkts = 0, bsid_pkts = 0;
3043 while (n_left_from > 0)
3047 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3050 while (n_left_from >= 8 && n_left_to_next >= 4)
3052 u32 bi0, bi1, bi2, bi3;
3053 vlib_buffer_t *b0, *b1, *b2, *b3;
3054 u32 next0, next1, next2, next3;
3055 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3056 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3057 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3058 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3059 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3061 /* Prefetch next iteration. */
3063 vlib_buffer_t *p4, *p5, *p6, *p7;
3065 p4 = vlib_get_buffer (vm, from[4]);
3066 p5 = vlib_get_buffer (vm, from[5]);
3067 p6 = vlib_get_buffer (vm, from[6]);
3068 p7 = vlib_get_buffer (vm, from[7]);
3070 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3071 vlib_prefetch_buffer_header (p4, LOAD);
3072 vlib_prefetch_buffer_header (p5, LOAD);
3073 vlib_prefetch_buffer_header (p6, LOAD);
3074 vlib_prefetch_buffer_header (p7, LOAD);
3076 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
3077 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
3078 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
3079 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
3082 to_next[0] = bi0 = from[0];
3083 to_next[1] = bi1 = from[1];
3084 to_next[2] = bi2 = from[2];
3085 to_next[3] = bi3 = from[3];
3089 n_left_to_next -= 4;
3091 b0 = vlib_get_buffer (vm, bi0);
3092 b1 = vlib_get_buffer (vm, bi1);
3093 b2 = vlib_get_buffer (vm, bi2);
3094 b3 = vlib_get_buffer (vm, bi3);
3097 pool_elt_at_index (sm->sid_lists,
3098 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3100 pool_elt_at_index (sm->sid_lists,
3101 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3103 pool_elt_at_index (sm->sid_lists,
3104 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3106 pool_elt_at_index (sm->sid_lists,
3107 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3108 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3109 vec_len (sl0->rewrite));
3110 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3111 vec_len (sl1->rewrite));
3112 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3113 vec_len (sl2->rewrite));
3114 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3115 vec_len (sl3->rewrite));
3117 ip0_encap = vlib_buffer_get_current (b0);
3118 ip1_encap = vlib_buffer_get_current (b1);
3119 ip2_encap = vlib_buffer_get_current (b2);
3120 ip3_encap = vlib_buffer_get_current (b3);
3123 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3126 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3129 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3132 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3135 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3136 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3137 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3138 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3140 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3141 sl0->rewrite, vec_len (sl0->rewrite));
3142 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3143 sl1->rewrite, vec_len (sl1->rewrite));
3144 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3145 sl2->rewrite, vec_len (sl2->rewrite));
3146 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3147 sl3->rewrite, vec_len (sl3->rewrite));
3149 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3150 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3151 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3152 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3154 ip0 = vlib_buffer_get_current (b0);
3155 ip1 = vlib_buffer_get_current (b1);
3156 ip2 = vlib_buffer_get_current (b2);
3157 ip3 = vlib_buffer_get_current (b3);
3159 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3160 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3161 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3162 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3164 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3166 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3168 sr_policy_rewrite_trace_t *tr =
3169 vlib_add_trace (vm, node, b0, sizeof (*tr));
3170 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3171 sizeof (tr->src.as_u8));
3172 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3173 sizeof (tr->dst.as_u8));
3176 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3178 sr_policy_rewrite_trace_t *tr =
3179 vlib_add_trace (vm, node, b1, sizeof (*tr));
3180 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3181 sizeof (tr->src.as_u8));
3182 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3183 sizeof (tr->dst.as_u8));
3186 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3188 sr_policy_rewrite_trace_t *tr =
3189 vlib_add_trace (vm, node, b2, sizeof (*tr));
3190 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3191 sizeof (tr->src.as_u8));
3192 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3193 sizeof (tr->dst.as_u8));
3196 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3198 sr_policy_rewrite_trace_t *tr =
3199 vlib_add_trace (vm, node, b3, sizeof (*tr));
3200 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3201 sizeof (tr->src.as_u8));
3202 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3203 sizeof (tr->dst.as_u8));
3208 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3209 n_left_to_next, bi0, bi1, bi2, bi3,
3210 next0, next1, next2, next3);
3213 /* Single loop for potentially the last three packets */
3214 while (n_left_from > 0 && n_left_to_next > 0)
3218 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3219 ip6_sr_header_t *sr0;
3221 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3228 n_left_to_next -= 1;
3229 b0 = vlib_get_buffer (vm, bi0);
3232 pool_elt_at_index (sm->sid_lists,
3233 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3234 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3235 vec_len (sl0->rewrite));
3237 ip0_encap = vlib_buffer_get_current (b0);
3239 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3241 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3243 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3244 sl0->rewrite, vec_len (sl0->rewrite));
3245 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3247 ip0 = vlib_buffer_get_current (b0);
3249 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3251 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3252 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3254 sr_policy_rewrite_trace_t *tr =
3255 vlib_add_trace (vm, node, b0, sizeof (*tr));
3256 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3257 sizeof (tr->src.as_u8));
3258 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3259 sizeof (tr->dst.as_u8));
3263 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3264 n_left_to_next, bi0, next0);
3267 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3270 /* Update counters */
3271 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3272 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3274 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3275 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3278 return from_frame->n_vectors;
3282 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3283 .function = sr_policy_rewrite_b_encaps,
3284 .name = "sr-pl-rewrite-b-encaps",
3285 .vector_size = sizeof (u32),
3286 .format_trace = format_sr_policy_rewrite_trace,
3287 .type = VLIB_NODE_TYPE_INTERNAL,
3288 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3289 .error_strings = sr_policy_rewrite_error_strings,
3290 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3292 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3293 foreach_sr_policy_rewrite_next
3299 /*************************** SR Policy plugins ******************************/
3301 * @brief SR Policy plugin registry
3304 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3305 u8 * keyword_str, u8 * def_str,
3306 u8 * params_str, u8 prefix_length,
3308 format_function_t * ls_format,
3309 unformat_function_t * ls_unformat,
3310 sr_p_plugin_callback_t * creation_fn,
3311 sr_p_plugin_callback_t * removal_fn)
3313 ip6_sr_main_t *sm = &sr_main;
3316 sr_policy_fn_registration_t *plugin;
3318 /* Did this function exist? If so update it */
3319 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3322 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3324 /* Else create a new one and set hash key */
3327 pool_get (sm->policy_plugin_functions, plugin);
3328 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3329 plugin - sm->policy_plugin_functions);
3332 clib_memset (plugin, 0, sizeof (*plugin));
3334 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3335 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3336 plugin->prefix_length = prefix_length;
3337 plugin->ls_format = ls_format;
3338 plugin->ls_unformat = ls_unformat;
3339 plugin->creation = creation_fn;
3340 plugin->removal = removal_fn;
3341 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3342 plugin->function_name = format (0, "%s%c", fn_name, 0);
3343 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3344 plugin->def_str = format (0, "%s%c", def_str, 0);
3345 plugin->params_str = format (0, "%s%c", params_str, 0);
3347 return plugin->sr_policy_function_number;
3351 * @brief CLI function to 'show' all available SR LocalSID behaviors
3353 static clib_error_t *
3354 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3355 unformat_input_t * input,
3356 vlib_cli_command_t * cmd)
3358 ip6_sr_main_t *sm = &sr_main;
3359 sr_policy_fn_registration_t *plugin;
3360 sr_policy_fn_registration_t **plugins_vec = 0;
3363 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3366 pool_foreach (plugin, sm->policy_plugin_functions,
3367 ({ vec_add1 (plugins_vec, plugin); }));
3370 vlib_cli_output (vm, "Plugin behaviors:\n");
3371 for (i = 0; i < vec_len (plugins_vec); i++)
3373 plugin = plugins_vec[i];
3374 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3376 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3382 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3383 .path = "show sr policy behaviors",
3384 .short_help = "show sr policy behaviors",
3385 .function = show_sr_policy_behaviors_command_fn,
3389 /*************************** SR Segment Lists DPOs ****************************/
3391 format_sr_segment_list_dpo (u8 * s, va_list * args)
3393 ip6_sr_main_t *sm = &sr_main;
3394 ip6_address_t *addr;
3397 index_t index = va_arg (*args, index_t);
3398 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3399 s = format (s, "SR: Segment List index:[%d]", index);
3400 s = format (s, "\n\tSegments:");
3402 sl = pool_elt_at_index (sm->sid_lists, index);
3404 s = format (s, "< ");
3405 vec_foreach (addr, sl->segments)
3407 s = format (s, "%U, ", format_ip6_address, addr);
3409 s = format (s, "\b\b > - ");
3410 s = format (s, "Weight: %u", sl->weight);
3415 const static dpo_vft_t sr_policy_rewrite_vft = {
3416 .dv_lock = sr_dpo_lock,
3417 .dv_unlock = sr_dpo_unlock,
3418 .dv_format = format_sr_segment_list_dpo,
3421 const static char *const sr_pr_encaps_ip6_nodes[] = {
3422 "sr-pl-rewrite-encaps",
3426 const static char *const sr_pr_encaps_ip4_nodes[] = {
3427 "sr-pl-rewrite-encaps-v4",
3431 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3432 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3433 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3436 const static char *const sr_pr_insert_ip6_nodes[] = {
3437 "sr-pl-rewrite-insert",
3441 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3442 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3445 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3446 "sr-pl-rewrite-b-insert",
3450 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3451 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3454 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3455 "sr-pl-rewrite-b-encaps",
3459 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3460 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3463 /********************* SR Policy Rewrite initialization ***********************/
3465 * @brief SR Policy Rewrite initialization
3468 sr_policy_rewrite_init (vlib_main_t * vm)
3470 ip6_sr_main_t *sm = &sr_main;
3472 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3473 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3474 sizeof (ip6_address_t));
3476 /* Init SR VPO DPOs type */
3477 sr_pr_encaps_dpo_type =
3478 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3480 sr_pr_insert_dpo_type =
3481 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3483 sr_pr_bsid_encaps_dpo_type =
3484 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3486 sr_pr_bsid_insert_dpo_type =
3487 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3489 /* Register the L2 encaps node used in HW redirect */
3490 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3492 sm->fib_table_ip6 = (u32) ~ 0;
3493 sm->fib_table_ip4 = (u32) ~ 0;
3498 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3502 * fd.io coding-style-patch-verification: ON
3505 * eval: (c-set-style "gnu")