2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip4_inlines.h>
45 #include <vnet/ip/ip6_inlines.h>
46 #include <vnet/srv6/sr_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
110 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
112 /******************* SR rewrite set encaps IPv6 source addr *******************/
113 /* Note: This is temporal. We don't know whether to follow this path or
114 take the ip address of a loopback interface or even the OIF */
117 sr_set_source (ip6_address_t * address)
119 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
123 sr_get_encaps_source ()
125 return &sr_pr_encaps_src;
128 static clib_error_t *
129 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130 vlib_cli_command_t * cmd)
132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
135 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
138 return clib_error_return (0, "No address specified");
140 return clib_error_return (0, "No address specified");
144 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145 .path = "set sr encaps source",
146 .short_help = "set sr encaps source addr <ip6_addr>",
147 .function = set_sr_src_command_fn,
151 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
154 sr_set_hop_limit (u8 hop_limit)
156 sr_pr_encaps_hop_limit = hop_limit;
160 sr_get_hop_limit (void)
162 return sr_pr_encaps_hop_limit;
165 static clib_error_t *
166 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167 vlib_cli_command_t * cmd)
169 int hop_limit = sr_get_hop_limit ();
171 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172 return clib_error_return (0, "No value specified");
173 if (!unformat (input, "%d", &hop_limit))
174 return clib_error_return (0, "Invalid value");
175 if (hop_limit <= 0 || hop_limit > 255)
176 return clib_error_return (0, "Value out of range [1-255]");
177 sr_pr_encaps_hop_limit = (u8) hop_limit;
182 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183 .path = "set sr encaps hop-limit",
184 .short_help = "set sr encaps hop-limit <value>",
185 .function = set_sr_hop_limit_command_fn,
189 /*********************** SR rewrite string computation ************************/
191 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
193 * @param sl is a vector of IPv6 addresses composing the Segment List
195 * @return precomputed rewrite string for encapsulation
198 compute_rewrite_encaps (ip6_address_t * sl)
201 ip6_sr_header_t *srh;
202 ip6_address_t *addrp, *this_address;
203 u32 header_length = 0;
207 header_length += IPv6_DEFAULT_HEADER_LENGTH;
208 if (vec_len (sl) > 1)
210 header_length += sizeof (ip6_sr_header_t);
211 header_length += vec_len (sl) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 iph = (ip6_header_t *) rs;
217 iph->ip_version_traffic_class_and_flow_label =
218 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
219 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
220 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
221 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
222 iph->protocol = IP_PROTOCOL_IPV6;
223 iph->hop_limit = sr_pr_encaps_hop_limit;
225 if (vec_len (sl) > 1)
227 srh = (ip6_sr_header_t *) (iph + 1);
228 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
229 srh->protocol = IP_PROTOCOL_IPV6;
230 srh->type = ROUTING_HEADER_TYPE_SR;
231 srh->segments_left = vec_len (sl) - 1;
232 srh->last_entry = vec_len (sl) - 1;
233 srh->length = ((sizeof (ip6_sr_header_t) +
234 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
237 addrp = srh->segments + vec_len (sl) - 1;
238 vec_foreach (this_address, sl)
240 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
241 sizeof (ip6_address_t));
245 iph->dst_address.as_u64[0] = sl->as_u64[0];
246 iph->dst_address.as_u64[1] = sl->as_u64[1];
251 * @brief SR rewrite string computation for SRH insertion (inline)
253 * @param sl is a vector of IPv6 addresses composing the Segment List
255 * @return precomputed rewrite string for SRH insertion
258 compute_rewrite_insert (ip6_address_t * sl)
260 ip6_sr_header_t *srh;
261 ip6_address_t *addrp, *this_address;
262 u32 header_length = 0;
266 header_length += sizeof (ip6_sr_header_t);
267 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
269 vec_validate (rs, header_length - 1);
271 srh = (ip6_sr_header_t *) rs;
272 srh->type = ROUTING_HEADER_TYPE_SR;
273 srh->segments_left = vec_len (sl);
274 srh->last_entry = vec_len (sl);
275 srh->length = ((sizeof (ip6_sr_header_t) +
276 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
279 addrp = srh->segments + vec_len (sl);
280 vec_foreach (this_address, sl)
282 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
283 sizeof (ip6_address_t));
290 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
292 * @param sl is a vector of IPv6 addresses composing the Segment List
294 * @return precomputed rewrite string for SRH insertion with BSID
297 compute_rewrite_bsid (ip6_address_t * sl)
299 ip6_sr_header_t *srh;
300 ip6_address_t *addrp, *this_address;
301 u32 header_length = 0;
305 header_length += sizeof (ip6_sr_header_t);
306 header_length += vec_len (sl) * sizeof (ip6_address_t);
308 vec_validate (rs, header_length - 1);
310 srh = (ip6_sr_header_t *) rs;
311 srh->type = ROUTING_HEADER_TYPE_SR;
312 srh->segments_left = vec_len (sl) - 1;
313 srh->last_entry = vec_len (sl) - 1;
314 srh->length = ((sizeof (ip6_sr_header_t) +
315 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
318 addrp = srh->segments + vec_len (sl) - 1;
319 vec_foreach (this_address, sl)
321 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
322 sizeof (ip6_address_t));
328 /*************************** SR LB helper functions **************************/
330 * @brief Creates a Segment List and adds it to an SR policy
332 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
333 * not necessarily unique. Hence there might be two Segment List within the
334 * same SR Policy with exactly the same segments and same weight.
336 * @param sr_policy is the SR policy where the SL will be added
337 * @param sl is a vector of IPv6 addresses composing the Segment List
338 * @param weight is the weight of the SegmentList (for load-balancing purposes)
339 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
341 * @return pointer to the just created segment list
343 static inline ip6_sr_sl_t *
344 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
347 ip6_sr_main_t *sm = &sr_main;
348 ip6_sr_sl_t *segment_list;
349 sr_policy_fn_registration_t *plugin = 0;
351 pool_get (sm->sid_lists, segment_list);
352 clib_memset (segment_list, 0, sizeof (*segment_list));
354 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
356 /* Fill in segment list */
357 segment_list->weight =
358 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
360 segment_list->segments = vec_dup (sl);
362 segment_list->egress_fib_table =
363 ip6_fib_index_from_table_id (sr_policy->fib_table);
367 segment_list->rewrite = compute_rewrite_encaps (sl);
368 segment_list->rewrite_bsid = segment_list->rewrite;
372 segment_list->rewrite = compute_rewrite_insert (sl);
373 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
376 if (sr_policy->plugin)
379 pool_elt_at_index (sm->policy_plugin_functions,
380 sr_policy->plugin - SR_BEHAVIOR_LAST);
382 segment_list->plugin = sr_policy->plugin;
383 segment_list->plugin_mem = sr_policy->plugin_mem;
385 plugin->creation (sr_policy);
389 dpo_reset (&segment_list->bsid_dpo);
390 dpo_reset (&segment_list->ip6_dpo);
391 dpo_reset (&segment_list->ip4_dpo);
395 if (!sr_policy->plugin)
397 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
398 DPO_PROTO_IP6, segment_list - sm->sid_lists);
399 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
400 DPO_PROTO_IP4, segment_list - sm->sid_lists);
401 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
402 DPO_PROTO_IP6, segment_list - sm->sid_lists);
406 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
407 segment_list - sm->sid_lists);
408 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
409 segment_list - sm->sid_lists);
410 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
411 segment_list - sm->sid_lists);
416 if (!sr_policy->plugin)
418 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
419 DPO_PROTO_IP6, segment_list - sm->sid_lists);
420 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
421 DPO_PROTO_IP6, segment_list - sm->sid_lists);
425 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
426 segment_list - sm->sid_lists);
427 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
428 segment_list - sm->sid_lists);
436 * @brief Updates the Load Balancer after an SR Policy change
438 * @param sr_policy is the modified SR Policy
441 update_lb (ip6_sr_policy_t * sr_policy)
443 flow_hash_config_t fhc;
445 ip6_sr_sl_t *segment_list;
446 ip6_sr_main_t *sm = &sr_main;
447 load_balance_path_t path;
448 path.path_index = FIB_NODE_INDEX_INVALID;
449 load_balance_path_t *ip4_path_vector = 0;
450 load_balance_path_t *ip6_path_vector = 0;
451 load_balance_path_t *b_path_vector = 0;
453 /* In case LB does not exist, create it */
454 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
457 .fp_proto = FIB_PROTOCOL_IP6,
460 .ip6 = sr_policy->bsid,
464 /* Add FIB entry for BSID */
465 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
468 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
469 load_balance_create (0, DPO_PROTO_IP6, fhc));
471 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
472 load_balance_create (0, DPO_PROTO_IP6, fhc));
474 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
475 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
476 sr_policy->fib_table),
478 FIB_ENTRY_FLAG_EXCLUSIVE,
479 &sr_policy->bsid_dpo);
481 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
484 FIB_ENTRY_FLAG_EXCLUSIVE,
485 &sr_policy->ip6_dpo);
487 if (sr_policy->is_encap)
489 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
490 load_balance_create (0, DPO_PROTO_IP4, fhc));
492 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
495 FIB_ENTRY_FLAG_EXCLUSIVE,
496 &sr_policy->ip4_dpo);
501 /* Create the LB path vector */
502 vec_foreach (sl_index, sr_policy->segments_lists)
504 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
505 path.path_dpo = segment_list->bsid_dpo;
506 path.path_weight = segment_list->weight;
507 vec_add1 (b_path_vector, path);
508 path.path_dpo = segment_list->ip6_dpo;
509 vec_add1 (ip6_path_vector, path);
510 if (sr_policy->is_encap)
512 path.path_dpo = segment_list->ip4_dpo;
513 vec_add1 (ip4_path_vector, path);
517 /* Update LB multipath */
518 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
519 LOAD_BALANCE_FLAG_NONE);
520 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
521 LOAD_BALANCE_FLAG_NONE);
522 if (sr_policy->is_encap)
523 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
524 LOAD_BALANCE_FLAG_NONE);
527 vec_free (b_path_vector);
528 vec_free (ip6_path_vector);
529 vec_free (ip4_path_vector);
533 * @brief Updates the Replicate DPO after an SR Policy change
535 * @param sr_policy is the modified SR Policy (type spray)
538 update_replicate (ip6_sr_policy_t * sr_policy)
541 ip6_sr_sl_t *segment_list;
542 ip6_sr_main_t *sm = &sr_main;
543 load_balance_path_t path;
544 path.path_index = FIB_NODE_INDEX_INVALID;
545 load_balance_path_t *b_path_vector = 0;
546 load_balance_path_t *ip6_path_vector = 0;
547 load_balance_path_t *ip4_path_vector = 0;
549 /* In case LB does not exist, create it */
550 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
552 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
553 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
555 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
556 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
558 /* Update FIB entry's DPO to point to SR without LB */
560 .fp_proto = FIB_PROTOCOL_IP6,
563 .ip6 = sr_policy->bsid,
566 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
567 sr_policy->fib_table),
569 FIB_ENTRY_FLAG_EXCLUSIVE,
570 &sr_policy->bsid_dpo);
572 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
575 FIB_ENTRY_FLAG_EXCLUSIVE,
576 &sr_policy->ip6_dpo);
578 if (sr_policy->is_encap)
580 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
581 replicate_create (0, DPO_PROTO_IP4));
583 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
586 FIB_ENTRY_FLAG_EXCLUSIVE,
587 &sr_policy->ip4_dpo);
592 /* Create the replicate path vector */
593 path.path_weight = 1;
594 vec_foreach (sl_index, sr_policy->segments_lists)
596 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
597 path.path_dpo = segment_list->bsid_dpo;
598 vec_add1 (b_path_vector, path);
599 path.path_dpo = segment_list->ip6_dpo;
600 vec_add1 (ip6_path_vector, path);
601 if (sr_policy->is_encap)
603 path.path_dpo = segment_list->ip4_dpo;
604 vec_add1 (ip4_path_vector, path);
608 /* Update replicate multipath */
609 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
610 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
611 if (sr_policy->is_encap)
612 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
615 /******************************* SR rewrite API *******************************/
616 /* Three functions for handling sr policies:
620 * All of them are API. CLI function on sr_policy_command_fn */
623 * @brief Create a new SR policy
625 * @param bsid is the bindingSID of the SR Policy
626 * @param segments is a vector of IPv6 address composing the segment list
627 * @param weight is the weight of the sid list. optional.
628 * @param behavior is the behavior of the SR policy. (default//spray)
629 * @param fib_table is the VRF where to install the FIB entry for the BSID
630 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
632 * @return 0 if correct, else error
635 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
636 u32 weight, u8 behavior, u32 fib_table, u8 is_encap,
637 u16 plugin, void *ls_plugin_mem)
639 ip6_sr_main_t *sm = &sr_main;
640 ip6_sr_policy_t *sr_policy = 0;
643 /* Search for existing keys (BSID) */
644 p = mhash_get (&sm->sr_policies_index_hash, bsid);
647 /* Add SR policy that already exists; complain */
651 /* Search collision in FIB entries */
652 /* Explanation: It might be possible that some other entity has already
653 * created a route for the BSID. This in theory is impossible, but in
654 * practise we could see it. Assert it and scream if needed */
656 .fp_proto = FIB_PROTOCOL_IP6,
663 /* Lookup the FIB index associated to the table selected */
664 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
665 (fib_table != (u32) ~ 0 ? fib_table : 0));
669 /* Lookup whether there exists an entry for the BSID */
670 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
671 if (FIB_NODE_INDEX_INVALID != fei)
672 return -12; //There is an entry for such lookup
674 /* Add an SR policy object */
675 pool_get (sm->sr_policies, sr_policy);
676 clib_memset (sr_policy, 0, sizeof (*sr_policy));
677 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
678 sr_policy->type = behavior;
679 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
680 sr_policy->is_encap = is_encap;
684 sr_policy->plugin = plugin;
685 sr_policy->plugin_mem = ls_plugin_mem;
689 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
692 /* Create a segment list and add the index to the SR policy */
693 create_sl (sr_policy, segments, weight, is_encap);
695 /* If FIB doesnt exist, create them */
696 if (sm->fib_table_ip6 == (u32) ~ 0)
698 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
700 "SRv6 steering of IP6 prefixes through BSIDs");
701 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
703 "SRv6 steering of IP4 prefixes through BSIDs");
706 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
707 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
708 update_lb (sr_policy);
709 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
710 update_replicate (sr_policy);
715 * @brief Delete a SR policy
717 * @param bsid is the bindingSID of the SR Policy
718 * @param index is the index of the SR policy
720 * @return 0 if correct, else error
723 sr_policy_del (ip6_address_t * bsid, u32 index)
725 ip6_sr_main_t *sm = &sr_main;
726 ip6_sr_policy_t *sr_policy = 0;
727 ip6_sr_sl_t *segment_list;
733 p = mhash_get (&sm->sr_policies_index_hash, bsid);
735 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
741 sr_policy = pool_elt_at_index (sm->sr_policies, index);
746 /* Remove BindingSID FIB entry */
748 .fp_proto = FIB_PROTOCOL_IP6,
751 .ip6 = sr_policy->bsid,
756 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
757 sr_policy->fib_table),
758 &pfx, FIB_SOURCE_SR);
760 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
762 if (sr_policy->is_encap)
763 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
765 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
767 dpo_reset (&sr_policy->bsid_dpo);
768 dpo_reset (&sr_policy->ip4_dpo);
769 dpo_reset (&sr_policy->ip6_dpo);
772 /* Clean SID Lists */
773 vec_foreach (sl_index, sr_policy->segments_lists)
775 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
776 vec_free (segment_list->segments);
777 vec_free (segment_list->rewrite);
778 if (!sr_policy->is_encap)
779 vec_free (segment_list->rewrite_bsid);
780 pool_put_index (sm->sid_lists, *sl_index);
783 if (sr_policy->plugin)
785 sr_policy_fn_registration_t *plugin = 0;
788 pool_elt_at_index (sm->policy_plugin_functions,
789 sr_policy->plugin - SR_BEHAVIOR_LAST);
791 plugin->removal (sr_policy);
792 sr_policy->plugin = 0;
793 sr_policy->plugin_mem = NULL;
796 /* Remove SR policy entry */
797 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
798 pool_put (sm->sr_policies, sr_policy);
800 /* If FIB empty unlock it */
801 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
803 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
804 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
805 sm->fib_table_ip6 = (u32) ~ 0;
806 sm->fib_table_ip4 = (u32) ~ 0;
813 * @brief Modify an existing SR policy
815 * The possible modifications are adding a new Segment List, modifying an
816 * existing Segment List (modify the weight only) and delete a given
817 * Segment List from the SR Policy.
819 * @param bsid is the bindingSID of the SR Policy
820 * @param index is the index of the SR policy
821 * @param fib_table is the VRF where to install the FIB entry for the BSID
822 * @param operation is the operation to perform (among the top ones)
823 * @param segments is a vector of IPv6 address composing the segment list
824 * @param sl_index is the index of the Segment List to modify/delete
825 * @param weight is the weight of the sid list. optional.
826 * @param is_encap Mode. Encapsulation or SRH insertion.
828 * @return 0 if correct, else error
831 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
832 u8 operation, ip6_address_t * segments, u32 sl_index,
835 ip6_sr_main_t *sm = &sr_main;
836 ip6_sr_policy_t *sr_policy = 0;
837 ip6_sr_sl_t *segment_list;
838 u32 *sl_index_iterate;
843 p = mhash_get (&sm->sr_policies_index_hash, bsid);
845 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
851 sr_policy = pool_elt_at_index (sm->sr_policies, index);
856 if (operation == 1) /* Add SR List to an existing SR policy */
858 /* Create the new SL */
860 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
862 /* Create a new LB DPO */
863 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
864 update_lb (sr_policy);
865 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
866 update_replicate (sr_policy);
868 else if (operation == 2) /* Delete SR List from an existing SR policy */
870 /* Check that currently there are more than one SID list */
871 if (vec_len (sr_policy->segments_lists) == 1)
874 /* Check that the SR list does exist and is assigned to the sr policy */
875 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
876 if (*sl_index_iterate == sl_index)
879 if (*sl_index_iterate != sl_index)
882 /* Remove the lucky SR list that is being kicked out */
883 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
884 vec_free (segment_list->segments);
885 vec_free (segment_list->rewrite);
886 if (!sr_policy->is_encap)
887 vec_free (segment_list->rewrite_bsid);
888 pool_put_index (sm->sid_lists, sl_index);
889 vec_del1 (sr_policy->segments_lists,
890 sl_index_iterate - sr_policy->segments_lists);
892 /* Create a new LB DPO */
893 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
894 update_lb (sr_policy);
895 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
896 update_replicate (sr_policy);
898 else if (operation == 3) /* Modify the weight of an existing SR List */
900 /* Find the corresponding SL */
901 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
902 if (*sl_index_iterate == sl_index)
905 if (*sl_index_iterate != sl_index)
908 /* Change the weight */
909 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
910 segment_list->weight = weight;
913 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
914 update_lb (sr_policy);
916 else /* Incorrect op. */
923 * @brief CLI for 'sr policies' command family
925 static clib_error_t *
926 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
927 vlib_cli_command_t * cmd)
929 ip6_sr_main_t *sm = &sr_main;
931 char is_del = 0, is_add = 0, is_mod = 0;
933 ip6_address_t bsid, next_address;
934 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
935 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
936 ip6_address_t *segments = 0, *this_seg;
941 void *ls_plugin_mem = 0;
943 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
945 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
947 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
949 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
952 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
954 else if (!is_add && !policy_set
955 && unformat (input, "index %d", &sr_policy_index))
957 else if (unformat (input, "weight %d", &weight));
959 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
961 vec_add2 (segments, this_seg, 1);
962 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
965 else if (unformat (input, "add sl"))
967 else if (unformat (input, "del sl index %d", &sl_index))
969 else if (unformat (input, "mod sl index %d", &sl_index))
971 else if (fib_table == (u32) ~ 0
972 && unformat (input, "fib-table %d", &fib_table));
973 else if (unformat (input, "encap"))
975 else if (unformat (input, "insert"))
977 else if (unformat (input, "spray"))
979 else if (!behavior && unformat (input, "behavior"))
981 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
982 sr_policy_fn_registration_t **plugin_it = 0;
985 pool_foreach (plugin, sm->policy_plugin_functions)
987 vec_add1 (vec_plugins, plugin);
991 vec_foreach (plugin_it, vec_plugins)
994 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
996 behavior = (*plugin_it)->sr_policy_function_number;
1003 return clib_error_return (0, "Invalid behavior");
1010 if (!is_add && !is_mod && !is_del)
1011 return clib_error_return (0, "Incorrect CLI");
1014 return clib_error_return (0, "No SR policy BSID or index specified");
1018 if (behavior && vec_len (segments) == 0)
1020 vec_add2 (segments, this_seg, 1);
1021 clib_memset (this_seg, 0, sizeof (*this_seg));
1024 if (vec_len (segments) == 0)
1025 return clib_error_return (0, "No Segment List specified");
1027 rv = sr_policy_add (&bsid, segments, weight,
1028 (is_spray ? SR_POLICY_TYPE_SPRAY :
1029 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap,
1030 behavior, ls_plugin_mem);
1032 vec_free (segments);
1035 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1040 return clib_error_return (0, "No SL modification specified");
1041 if (operation != 1 && sl_index == (u32) ~ 0)
1042 return clib_error_return (0, "No Segment List index specified");
1043 if (operation == 1 && vec_len (segments) == 0)
1044 return clib_error_return (0, "No Segment List specified");
1045 if (operation == 3 && weight == (u32) ~ 0)
1046 return clib_error_return (0, "No new weight for the SL specified");
1048 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1049 sr_policy_index, fib_table, operation, segments,
1053 vec_free (segments);
1063 return clib_error_return (0,
1064 "There is already a FIB entry for the BindingSID address.\n"
1065 "The SR policy could not be created.");
1067 return clib_error_return (0, "The specified FIB table does not exist.");
1069 return clib_error_return (0,
1070 "The selected SR policy only contains ONE segment list. "
1071 "Please remove the SR policy instead");
1073 return clib_error_return (0,
1074 "Could not delete the segment list. "
1075 "It is not associated with that SR policy.");
1077 return clib_error_return (0,
1078 "Could not modify the segment list. "
1079 "The given SL is not associated with such SR policy.");
1081 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1087 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1088 .path = "sr policy",
1089 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1090 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1092 "Manipulation of SR policies.\n"
1093 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1094 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1095 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1096 "Each SR policy will be associated with a unique BindingSID.\n"
1097 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1098 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1099 "The add command will create a SR policy with its first segment list (sl)\n"
1100 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1101 "within an SR policy.\n"
1102 "The del command allows you to delete a SR policy along with all its associated\n"
1104 .function = sr_policy_command_fn,
1109 * @brief CLI to display onscreen all the SR policies
1111 static clib_error_t *
1112 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1113 vlib_cli_command_t * cmd)
1115 ip6_sr_main_t *sm = &sr_main;
1117 ip6_sr_sl_t *segment_list = 0;
1118 ip6_sr_policy_t *sr_policy = 0;
1119 ip6_sr_policy_t **vec_policies = 0;
1120 ip6_address_t *addr;
1124 vlib_cli_output (vm, "SR policies:");
1127 pool_foreach (sr_policy, sm->sr_policies)
1128 {vec_add1 (vec_policies, sr_policy); }
1131 vec_foreach_index (i, vec_policies)
1133 sr_policy = vec_policies[i];
1134 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1135 (u32) (sr_policy - sm->sr_policies),
1136 format_ip6_address, &sr_policy->bsid);
1137 vlib_cli_output (vm, "\tBehavior: %s",
1138 (sr_policy->is_encap ? "Encapsulation" :
1140 vlib_cli_output (vm, "\tType: %s",
1142 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
1143 vlib_cli_output (vm, "\tFIB table: %u",
1144 (sr_policy->fib_table !=
1145 (u32) ~ 0 ? sr_policy->fib_table : 0));
1146 vlib_cli_output (vm, "\tSegment Lists:");
1147 vec_foreach (sl_index, sr_policy->segments_lists)
1150 s = format (s, "\t[%u].- ", *sl_index);
1151 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1152 s = format (s, "< ");
1153 vec_foreach (addr, segment_list->segments)
1155 s = format (s, "%U, ", format_ip6_address, addr);
1157 s = format (s, "\b\b > ");
1158 s = format (s, "weight: %u", segment_list->weight);
1159 vlib_cli_output (vm, " %v", s);
1161 vlib_cli_output (vm, "-----------");
1167 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1168 .path = "show sr policies",
1169 .short_help = "show sr policies",
1170 .function = show_sr_policies_command_fn,
1175 * @brief CLI to display onscreen the SR encaps source addr
1177 static clib_error_t *
1178 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1179 vlib_cli_command_t * cmd)
1181 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1182 sr_get_encaps_source ());
1188 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1189 .path = "show sr encaps source addr",
1190 .short_help = "show sr encaps source addr",
1191 .function = show_sr_encaps_source_command_fn,
1196 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1198 static clib_error_t *
1199 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1200 unformat_input_t * input,
1201 vlib_cli_command_t * cmd)
1203 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1209 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1210 .path = "show sr encaps hop-limit",
1211 .short_help = "show sr encaps hop-limit",
1212 .function = show_sr_encaps_hop_limit_command_fn,
1216 /*************************** SR rewrite graph node ****************************/
1218 * @brief Trace for the SR Policy Rewrite graph node
1221 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1224 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1225 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1226 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1229 (s, "SR-policy-rewrite: src %U dst %U",
1230 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1236 * @brief IPv6 encapsulation processing as per RFC2473
1238 static_always_inline void
1239 encaps_processing_v6 (vlib_node_runtime_t * node,
1241 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1246 ip0_encap->hop_limit -= 1;
1248 ip0->payload_length + sizeof (ip6_header_t) +
1249 clib_net_to_host_u16 (ip0_encap->payload_length);
1250 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1252 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1253 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1255 (clib_net_to_host_u32 (
1256 ip0_encap->ip_version_traffic_class_and_flow_label) &
1258 (flow_label & 0x0000ffff));
1262 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1265 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1266 vlib_frame_t * from_frame)
1268 ip6_sr_main_t *sm = &sr_main;
1269 u32 n_left_from, next_index, *from, *to_next;
1271 from = vlib_frame_vector_args (from_frame);
1272 n_left_from = from_frame->n_vectors;
1274 next_index = node->cached_next_index;
1276 int encap_pkts = 0, bsid_pkts = 0;
1278 while (n_left_from > 0)
1282 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1285 while (n_left_from >= 8 && n_left_to_next >= 4)
1287 u32 bi0, bi1, bi2, bi3;
1288 vlib_buffer_t *b0, *b1, *b2, *b3;
1289 u32 next0, next1, next2, next3;
1290 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1291 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1292 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1293 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1295 /* Prefetch next iteration. */
1297 vlib_buffer_t *p4, *p5, *p6, *p7;
1299 p4 = vlib_get_buffer (vm, from[4]);
1300 p5 = vlib_get_buffer (vm, from[5]);
1301 p6 = vlib_get_buffer (vm, from[6]);
1302 p7 = vlib_get_buffer (vm, from[7]);
1304 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1305 vlib_prefetch_buffer_header (p4, LOAD);
1306 vlib_prefetch_buffer_header (p5, LOAD);
1307 vlib_prefetch_buffer_header (p6, LOAD);
1308 vlib_prefetch_buffer_header (p7, LOAD);
1310 clib_prefetch_store (p4->data);
1311 clib_prefetch_store (p5->data);
1312 clib_prefetch_store (p6->data);
1313 clib_prefetch_store (p7->data);
1316 to_next[0] = bi0 = from[0];
1317 to_next[1] = bi1 = from[1];
1318 to_next[2] = bi2 = from[2];
1319 to_next[3] = bi3 = from[3];
1323 n_left_to_next -= 4;
1325 b0 = vlib_get_buffer (vm, bi0);
1326 b1 = vlib_get_buffer (vm, bi1);
1327 b2 = vlib_get_buffer (vm, bi2);
1328 b3 = vlib_get_buffer (vm, bi3);
1331 pool_elt_at_index (sm->sid_lists,
1332 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1334 pool_elt_at_index (sm->sid_lists,
1335 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1337 pool_elt_at_index (sm->sid_lists,
1338 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1340 pool_elt_at_index (sm->sid_lists,
1341 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1343 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1344 vec_len (sl0->rewrite));
1345 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1346 vec_len (sl1->rewrite));
1347 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1348 vec_len (sl2->rewrite));
1349 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1350 vec_len (sl3->rewrite));
1352 ip0_encap = vlib_buffer_get_current (b0);
1353 ip1_encap = vlib_buffer_get_current (b1);
1354 ip2_encap = vlib_buffer_get_current (b2);
1355 ip3_encap = vlib_buffer_get_current (b3);
1357 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1358 sl0->rewrite, vec_len (sl0->rewrite));
1359 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1360 sl1->rewrite, vec_len (sl1->rewrite));
1361 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1362 sl2->rewrite, vec_len (sl2->rewrite));
1363 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1364 sl3->rewrite, vec_len (sl3->rewrite));
1366 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1367 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1368 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1369 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1371 ip0 = vlib_buffer_get_current (b0);
1372 ip1 = vlib_buffer_get_current (b1);
1373 ip2 = vlib_buffer_get_current (b2);
1374 ip3 = vlib_buffer_get_current (b3);
1376 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1377 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1378 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1379 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1381 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1382 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1383 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1384 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1386 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1388 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1390 sr_policy_rewrite_trace_t *tr =
1391 vlib_add_trace (vm, node, b0, sizeof (*tr));
1392 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1393 sizeof (tr->src.as_u8));
1394 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1395 sizeof (tr->dst.as_u8));
1398 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1400 sr_policy_rewrite_trace_t *tr =
1401 vlib_add_trace (vm, node, b1, sizeof (*tr));
1402 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1403 sizeof (tr->src.as_u8));
1404 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1405 sizeof (tr->dst.as_u8));
1408 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1410 sr_policy_rewrite_trace_t *tr =
1411 vlib_add_trace (vm, node, b2, sizeof (*tr));
1412 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1413 sizeof (tr->src.as_u8));
1414 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1415 sizeof (tr->dst.as_u8));
1418 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1420 sr_policy_rewrite_trace_t *tr =
1421 vlib_add_trace (vm, node, b3, sizeof (*tr));
1422 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1423 sizeof (tr->src.as_u8));
1424 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1425 sizeof (tr->dst.as_u8));
1430 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1431 n_left_to_next, bi0, bi1, bi2, bi3,
1432 next0, next1, next2, next3);
1435 /* Single loop for potentially the last three packets */
1436 while (n_left_from > 0 && n_left_to_next > 0)
1440 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1442 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1449 n_left_to_next -= 1;
1450 b0 = vlib_get_buffer (vm, bi0);
1453 pool_elt_at_index (sm->sid_lists,
1454 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1455 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1456 vec_len (sl0->rewrite));
1458 ip0_encap = vlib_buffer_get_current (b0);
1460 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1461 sl0->rewrite, vec_len (sl0->rewrite));
1462 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1464 ip0 = vlib_buffer_get_current (b0);
1466 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1468 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1470 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1471 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1473 sr_policy_rewrite_trace_t *tr =
1474 vlib_add_trace (vm, node, b0, sizeof (*tr));
1475 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1476 sizeof (tr->src.as_u8));
1477 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1478 sizeof (tr->dst.as_u8));
1482 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1483 n_left_to_next, bi0, next0);
1486 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1489 /* Update counters */
1490 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1491 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1493 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1494 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1497 return from_frame->n_vectors;
1501 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1502 .function = sr_policy_rewrite_encaps,
1503 .name = "sr-pl-rewrite-encaps",
1504 .vector_size = sizeof (u32),
1505 .format_trace = format_sr_policy_rewrite_trace,
1506 .type = VLIB_NODE_TYPE_INTERNAL,
1507 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1508 .error_strings = sr_policy_rewrite_error_strings,
1509 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1511 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1512 foreach_sr_policy_rewrite_next
1519 * @brief IPv4 encapsulation processing as per RFC2473
1521 static_always_inline void
1522 encaps_processing_v4 (vlib_node_runtime_t * node,
1524 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1527 ip6_sr_header_t *sr0;
1532 /* Inner IPv4: Decrement TTL & update checksum */
1533 ip0_encap->ttl -= 1;
1534 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1535 checksum0 += checksum0 >= 0xffff;
1536 ip0_encap->checksum = checksum0;
1538 /* Outer IPv6: Update length, FL, proto */
1539 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1540 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1541 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1542 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1543 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1544 (flow_label & 0x0000ffff));
1545 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1547 sr0 = (void *) (ip0 + 1);
1548 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1551 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1555 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1558 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1559 vlib_frame_t * from_frame)
1561 ip6_sr_main_t *sm = &sr_main;
1562 u32 n_left_from, next_index, *from, *to_next;
1564 from = vlib_frame_vector_args (from_frame);
1565 n_left_from = from_frame->n_vectors;
1567 next_index = node->cached_next_index;
1569 int encap_pkts = 0, bsid_pkts = 0;
1571 while (n_left_from > 0)
1575 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1578 while (n_left_from >= 8 && n_left_to_next >= 4)
1580 u32 bi0, bi1, bi2, bi3;
1581 vlib_buffer_t *b0, *b1, *b2, *b3;
1582 u32 next0, next1, next2, next3;
1583 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1584 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1585 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1586 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1588 /* Prefetch next iteration. */
1590 vlib_buffer_t *p4, *p5, *p6, *p7;
1592 p4 = vlib_get_buffer (vm, from[4]);
1593 p5 = vlib_get_buffer (vm, from[5]);
1594 p6 = vlib_get_buffer (vm, from[6]);
1595 p7 = vlib_get_buffer (vm, from[7]);
1597 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1598 vlib_prefetch_buffer_header (p4, LOAD);
1599 vlib_prefetch_buffer_header (p5, LOAD);
1600 vlib_prefetch_buffer_header (p6, LOAD);
1601 vlib_prefetch_buffer_header (p7, LOAD);
1603 clib_prefetch_store (p4->data);
1604 clib_prefetch_store (p5->data);
1605 clib_prefetch_store (p6->data);
1606 clib_prefetch_store (p7->data);
1609 to_next[0] = bi0 = from[0];
1610 to_next[1] = bi1 = from[1];
1611 to_next[2] = bi2 = from[2];
1612 to_next[3] = bi3 = from[3];
1616 n_left_to_next -= 4;
1618 b0 = vlib_get_buffer (vm, bi0);
1619 b1 = vlib_get_buffer (vm, bi1);
1620 b2 = vlib_get_buffer (vm, bi2);
1621 b3 = vlib_get_buffer (vm, bi3);
1624 pool_elt_at_index (sm->sid_lists,
1625 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1627 pool_elt_at_index (sm->sid_lists,
1628 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1630 pool_elt_at_index (sm->sid_lists,
1631 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1633 pool_elt_at_index (sm->sid_lists,
1634 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1635 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1636 vec_len (sl0->rewrite));
1637 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1638 vec_len (sl1->rewrite));
1639 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1640 vec_len (sl2->rewrite));
1641 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1642 vec_len (sl3->rewrite));
1644 ip0_encap = vlib_buffer_get_current (b0);
1645 ip1_encap = vlib_buffer_get_current (b1);
1646 ip2_encap = vlib_buffer_get_current (b2);
1647 ip3_encap = vlib_buffer_get_current (b3);
1649 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1650 sl0->rewrite, vec_len (sl0->rewrite));
1651 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1652 sl1->rewrite, vec_len (sl1->rewrite));
1653 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1654 sl2->rewrite, vec_len (sl2->rewrite));
1655 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1656 sl3->rewrite, vec_len (sl3->rewrite));
1658 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1659 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1660 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1661 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1663 ip0 = vlib_buffer_get_current (b0);
1664 ip1 = vlib_buffer_get_current (b1);
1665 ip2 = vlib_buffer_get_current (b2);
1666 ip3 = vlib_buffer_get_current (b3);
1668 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1669 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1670 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1671 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1673 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1674 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1675 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1676 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1678 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1680 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1682 sr_policy_rewrite_trace_t *tr =
1683 vlib_add_trace (vm, node, b0, sizeof (*tr));
1684 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1685 sizeof (tr->src.as_u8));
1686 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1687 sizeof (tr->dst.as_u8));
1690 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1692 sr_policy_rewrite_trace_t *tr =
1693 vlib_add_trace (vm, node, b1, sizeof (*tr));
1694 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1695 sizeof (tr->src.as_u8));
1696 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1697 sizeof (tr->dst.as_u8));
1700 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1702 sr_policy_rewrite_trace_t *tr =
1703 vlib_add_trace (vm, node, b2, sizeof (*tr));
1704 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1705 sizeof (tr->src.as_u8));
1706 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1707 sizeof (tr->dst.as_u8));
1710 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1712 sr_policy_rewrite_trace_t *tr =
1713 vlib_add_trace (vm, node, b3, sizeof (*tr));
1714 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1715 sizeof (tr->src.as_u8));
1716 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1717 sizeof (tr->dst.as_u8));
1722 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1723 n_left_to_next, bi0, bi1, bi2, bi3,
1724 next0, next1, next2, next3);
1727 /* Single loop for potentially the last three packets */
1728 while (n_left_from > 0 && n_left_to_next > 0)
1732 ip6_header_t *ip0 = 0;
1733 ip4_header_t *ip0_encap = 0;
1735 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1742 n_left_to_next -= 1;
1743 b0 = vlib_get_buffer (vm, bi0);
1746 pool_elt_at_index (sm->sid_lists,
1747 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1748 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1749 vec_len (sl0->rewrite));
1751 ip0_encap = vlib_buffer_get_current (b0);
1753 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1754 sl0->rewrite, vec_len (sl0->rewrite));
1755 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1757 ip0 = vlib_buffer_get_current (b0);
1759 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1761 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1763 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1764 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1766 sr_policy_rewrite_trace_t *tr =
1767 vlib_add_trace (vm, node, b0, sizeof (*tr));
1768 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1769 sizeof (tr->src.as_u8));
1770 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1771 sizeof (tr->dst.as_u8));
1775 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1776 n_left_to_next, bi0, next0);
1779 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1782 /* Update counters */
1783 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1784 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1786 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1787 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1790 return from_frame->n_vectors;
1794 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1795 .function = sr_policy_rewrite_encaps_v4,
1796 .name = "sr-pl-rewrite-encaps-v4",
1797 .vector_size = sizeof (u32),
1798 .format_trace = format_sr_policy_rewrite_trace,
1799 .type = VLIB_NODE_TYPE_INTERNAL,
1800 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1801 .error_strings = sr_policy_rewrite_error_strings,
1802 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1804 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1805 foreach_sr_policy_rewrite_next
1812 ip_flow_hash (void *data)
1814 ip4_header_t *iph = (ip4_header_t *) data;
1816 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1817 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1819 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1825 return (*((u64 *) m) & 0xffffffffffff);
1829 l2_flow_hash (vlib_buffer_t * b0)
1831 ethernet_header_t *eh;
1833 uword is_ip, eh_size;
1836 eh = vlib_buffer_get_current (b0);
1837 eh_type = clib_net_to_host_u16 (eh->type);
1838 eh_size = ethernet_buffer_header_size (b0);
1840 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1842 /* since we have 2 cache lines, use them */
1844 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1848 b = mac_to_u64 ((u8 *) eh->dst_address);
1849 c = mac_to_u64 ((u8 *) eh->src_address);
1850 hash_mix64 (a, b, c);
1856 * @brief Graph node for applying a SR policy into a L2 frame
1859 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1860 vlib_frame_t * from_frame)
1862 ip6_sr_main_t *sm = &sr_main;
1863 u32 n_left_from, next_index, *from, *to_next;
1865 from = vlib_frame_vector_args (from_frame);
1866 n_left_from = from_frame->n_vectors;
1868 next_index = node->cached_next_index;
1870 int encap_pkts = 0, bsid_pkts = 0;
1872 while (n_left_from > 0)
1876 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1879 while (n_left_from >= 8 && n_left_to_next >= 4)
1881 u32 bi0, bi1, bi2, bi3;
1882 vlib_buffer_t *b0, *b1, *b2, *b3;
1883 u32 next0, next1, next2, next3;
1884 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1885 ethernet_header_t *en0, *en1, *en2, *en3;
1886 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1887 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1888 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1889 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1890 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1892 /* Prefetch next iteration. */
1894 vlib_buffer_t *p4, *p5, *p6, *p7;
1896 p4 = vlib_get_buffer (vm, from[4]);
1897 p5 = vlib_get_buffer (vm, from[5]);
1898 p6 = vlib_get_buffer (vm, from[6]);
1899 p7 = vlib_get_buffer (vm, from[7]);
1901 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1902 vlib_prefetch_buffer_header (p4, LOAD);
1903 vlib_prefetch_buffer_header (p5, LOAD);
1904 vlib_prefetch_buffer_header (p6, LOAD);
1905 vlib_prefetch_buffer_header (p7, LOAD);
1907 clib_prefetch_store (p4->data);
1908 clib_prefetch_store (p5->data);
1909 clib_prefetch_store (p6->data);
1910 clib_prefetch_store (p7->data);
1913 to_next[0] = bi0 = from[0];
1914 to_next[1] = bi1 = from[1];
1915 to_next[2] = bi2 = from[2];
1916 to_next[3] = bi3 = from[3];
1920 n_left_to_next -= 4;
1922 b0 = vlib_get_buffer (vm, bi0);
1923 b1 = vlib_get_buffer (vm, bi1);
1924 b2 = vlib_get_buffer (vm, bi2);
1925 b3 = vlib_get_buffer (vm, bi3);
1927 sp0 = pool_elt_at_index (sm->sr_policies,
1928 sm->sw_iface_sr_policies[vnet_buffer
1932 sp1 = pool_elt_at_index (sm->sr_policies,
1933 sm->sw_iface_sr_policies[vnet_buffer
1937 sp2 = pool_elt_at_index (sm->sr_policies,
1938 sm->sw_iface_sr_policies[vnet_buffer
1942 sp3 = pool_elt_at_index (sm->sr_policies,
1943 sm->sw_iface_sr_policies[vnet_buffer
1946 flow_label0 = l2_flow_hash (b0);
1947 flow_label1 = l2_flow_hash (b1);
1948 flow_label2 = l2_flow_hash (b2);
1949 flow_label3 = l2_flow_hash (b3);
1951 if (vec_len (sp0->segments_lists) == 1)
1952 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1955 vnet_buffer (b0)->ip.flow_hash = flow_label0;
1956 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1957 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1958 (vec_len (sp0->segments_lists) - 1))];
1961 if (vec_len (sp1->segments_lists) == 1)
1962 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1965 vnet_buffer (b1)->ip.flow_hash = flow_label1;
1966 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1967 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1968 (vec_len (sp1->segments_lists) - 1))];
1971 if (vec_len (sp2->segments_lists) == 1)
1972 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1975 vnet_buffer (b2)->ip.flow_hash = flow_label2;
1976 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1977 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1978 (vec_len (sp2->segments_lists) - 1))];
1981 if (vec_len (sp3->segments_lists) == 1)
1982 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1985 vnet_buffer (b3)->ip.flow_hash = flow_label3;
1986 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1987 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1988 (vec_len (sp3->segments_lists) - 1))];
1992 pool_elt_at_index (sm->sid_lists,
1993 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1995 pool_elt_at_index (sm->sid_lists,
1996 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1998 pool_elt_at_index (sm->sid_lists,
1999 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2001 pool_elt_at_index (sm->sid_lists,
2002 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2004 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2005 vec_len (sl0->rewrite));
2006 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2007 vec_len (sl1->rewrite));
2008 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2009 vec_len (sl2->rewrite));
2010 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2011 vec_len (sl3->rewrite));
2013 en0 = vlib_buffer_get_current (b0);
2014 en1 = vlib_buffer_get_current (b1);
2015 en2 = vlib_buffer_get_current (b2);
2016 en3 = vlib_buffer_get_current (b3);
2018 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2019 sl0->rewrite, vec_len (sl0->rewrite));
2020 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2021 sl1->rewrite, vec_len (sl1->rewrite));
2022 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2023 sl2->rewrite, vec_len (sl2->rewrite));
2024 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2025 sl3->rewrite, vec_len (sl3->rewrite));
2027 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2028 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2029 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2030 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2032 ip0 = vlib_buffer_get_current (b0);
2033 ip1 = vlib_buffer_get_current (b1);
2034 ip2 = vlib_buffer_get_current (b2);
2035 ip3 = vlib_buffer_get_current (b3);
2037 ip0->payload_length =
2038 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2039 ip1->payload_length =
2040 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2041 ip2->payload_length =
2042 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2043 ip3->payload_length =
2044 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2046 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2048 sr0 = (void *) (ip0 + 1);
2049 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2052 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2054 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2056 sr1 = (void *) (ip1 + 1);
2057 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2060 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2062 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2064 sr2 = (void *) (ip2 + 1);
2065 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2068 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2070 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2072 sr3 = (void *) (ip3 + 1);
2073 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2076 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2078 /* TC is set to 0 for all ethernet frames, should be taken from COS
2079 * od DSCP of encapsulated packet in the future */
2080 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2081 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2082 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2083 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2084 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2085 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2086 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2087 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2089 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2091 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2093 sr_policy_rewrite_trace_t *tr =
2094 vlib_add_trace (vm, node, b0, sizeof (*tr));
2095 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2096 sizeof (tr->src.as_u8));
2097 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2098 sizeof (tr->dst.as_u8));
2101 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2103 sr_policy_rewrite_trace_t *tr =
2104 vlib_add_trace (vm, node, b1, sizeof (*tr));
2105 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2106 sizeof (tr->src.as_u8));
2107 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2108 sizeof (tr->dst.as_u8));
2111 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2113 sr_policy_rewrite_trace_t *tr =
2114 vlib_add_trace (vm, node, b2, sizeof (*tr));
2115 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2116 sizeof (tr->src.as_u8));
2117 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2118 sizeof (tr->dst.as_u8));
2121 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2123 sr_policy_rewrite_trace_t *tr =
2124 vlib_add_trace (vm, node, b3, sizeof (*tr));
2125 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2126 sizeof (tr->src.as_u8));
2127 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2128 sizeof (tr->dst.as_u8));
2133 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2134 n_left_to_next, bi0, bi1, bi2, bi3,
2135 next0, next1, next2, next3);
2138 /* Single loop for potentially the last three packets */
2139 while (n_left_from > 0 && n_left_to_next > 0)
2143 ip6_header_t *ip0 = 0;
2144 ip6_sr_header_t *sr0;
2145 ethernet_header_t *en0;
2146 ip6_sr_policy_t *sp0;
2148 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2156 n_left_to_next -= 1;
2157 b0 = vlib_get_buffer (vm, bi0);
2159 /* Find the SR policy */
2160 sp0 = pool_elt_at_index (sm->sr_policies,
2161 sm->sw_iface_sr_policies[vnet_buffer
2164 flow_label0 = l2_flow_hash (b0);
2166 /* In case there is more than one SL, LB among them */
2167 if (vec_len (sp0->segments_lists) == 1)
2168 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2171 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2172 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2173 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2174 (vec_len (sp0->segments_lists) - 1))];
2177 pool_elt_at_index (sm->sid_lists,
2178 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2179 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2180 vec_len (sl0->rewrite));
2182 en0 = vlib_buffer_get_current (b0);
2184 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2185 sl0->rewrite, vec_len (sl0->rewrite));
2187 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2189 ip0 = vlib_buffer_get_current (b0);
2191 ip0->payload_length =
2192 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2194 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2196 sr0 = (void *) (ip0 + 1);
2197 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2200 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2202 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2203 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2205 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2206 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2208 sr_policy_rewrite_trace_t *tr =
2209 vlib_add_trace (vm, node, b0, sizeof (*tr));
2210 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2211 sizeof (tr->src.as_u8));
2212 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2213 sizeof (tr->dst.as_u8));
2217 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2218 n_left_to_next, bi0, next0);
2221 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2224 /* Update counters */
2225 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2226 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2228 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2229 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2232 return from_frame->n_vectors;
2236 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2237 .function = sr_policy_rewrite_encaps_l2,
2238 .name = "sr-pl-rewrite-encaps-l2",
2239 .vector_size = sizeof (u32),
2240 .format_trace = format_sr_policy_rewrite_trace,
2241 .type = VLIB_NODE_TYPE_INTERNAL,
2242 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2243 .error_strings = sr_policy_rewrite_error_strings,
2244 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2246 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2247 foreach_sr_policy_rewrite_next
2254 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2257 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2258 vlib_frame_t * from_frame)
2260 ip6_sr_main_t *sm = &sr_main;
2261 u32 n_left_from, next_index, *from, *to_next;
2263 from = vlib_frame_vector_args (from_frame);
2264 n_left_from = from_frame->n_vectors;
2266 next_index = node->cached_next_index;
2268 int insert_pkts = 0, bsid_pkts = 0;
2270 while (n_left_from > 0)
2274 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2277 while (n_left_from >= 8 && n_left_to_next >= 4)
2279 u32 bi0, bi1, bi2, bi3;
2280 vlib_buffer_t *b0, *b1, *b2, *b3;
2281 u32 next0, next1, next2, next3;
2282 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2283 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2284 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2285 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2286 u16 new_l0, new_l1, new_l2, new_l3;
2288 /* Prefetch next iteration. */
2290 vlib_buffer_t *p4, *p5, *p6, *p7;
2292 p4 = vlib_get_buffer (vm, from[4]);
2293 p5 = vlib_get_buffer (vm, from[5]);
2294 p6 = vlib_get_buffer (vm, from[6]);
2295 p7 = vlib_get_buffer (vm, from[7]);
2297 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2298 vlib_prefetch_buffer_header (p4, LOAD);
2299 vlib_prefetch_buffer_header (p5, LOAD);
2300 vlib_prefetch_buffer_header (p6, LOAD);
2301 vlib_prefetch_buffer_header (p7, LOAD);
2303 clib_prefetch_store (p4->data);
2304 clib_prefetch_store (p5->data);
2305 clib_prefetch_store (p6->data);
2306 clib_prefetch_store (p7->data);
2309 to_next[0] = bi0 = from[0];
2310 to_next[1] = bi1 = from[1];
2311 to_next[2] = bi2 = from[2];
2312 to_next[3] = bi3 = from[3];
2316 n_left_to_next -= 4;
2318 b0 = vlib_get_buffer (vm, bi0);
2319 b1 = vlib_get_buffer (vm, bi1);
2320 b2 = vlib_get_buffer (vm, bi2);
2321 b3 = vlib_get_buffer (vm, bi3);
2324 pool_elt_at_index (sm->sid_lists,
2325 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2327 pool_elt_at_index (sm->sid_lists,
2328 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2330 pool_elt_at_index (sm->sid_lists,
2331 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2333 pool_elt_at_index (sm->sid_lists,
2334 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2335 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2336 vec_len (sl0->rewrite));
2337 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2338 vec_len (sl1->rewrite));
2339 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2340 vec_len (sl2->rewrite));
2341 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2342 vec_len (sl3->rewrite));
2344 ip0 = vlib_buffer_get_current (b0);
2345 ip1 = vlib_buffer_get_current (b1);
2346 ip2 = vlib_buffer_get_current (b2);
2347 ip3 = vlib_buffer_get_current (b3);
2349 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2351 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2352 ip6_ext_header_len (ip0 + 1));
2354 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2356 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2358 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2359 ip6_ext_header_len (ip1 + 1));
2361 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2363 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2365 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2366 ip6_ext_header_len (ip2 + 1));
2368 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2370 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2372 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2373 ip6_ext_header_len (ip3 + 1));
2375 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2377 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2378 (void *) sr0 - (void *) ip0);
2379 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2380 (void *) sr1 - (void *) ip1);
2381 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2382 (void *) sr2 - (void *) ip2);
2383 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2384 (void *) sr3 - (void *) ip3);
2386 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2387 sl0->rewrite, vec_len (sl0->rewrite));
2388 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2389 sl1->rewrite, vec_len (sl1->rewrite));
2390 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2391 sl2->rewrite, vec_len (sl2->rewrite));
2392 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2393 sl3->rewrite, vec_len (sl3->rewrite));
2395 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2396 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2397 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2398 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2400 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2401 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2402 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2403 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2405 ip0->hop_limit -= 1;
2406 ip1->hop_limit -= 1;
2407 ip2->hop_limit -= 1;
2408 ip3->hop_limit -= 1;
2411 clib_net_to_host_u16 (ip0->payload_length) +
2412 vec_len (sl0->rewrite);
2414 clib_net_to_host_u16 (ip1->payload_length) +
2415 vec_len (sl1->rewrite);
2417 clib_net_to_host_u16 (ip2->payload_length) +
2418 vec_len (sl2->rewrite);
2420 clib_net_to_host_u16 (ip3->payload_length) +
2421 vec_len (sl3->rewrite);
2423 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2424 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2425 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2426 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2428 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2429 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2430 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2431 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2433 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2434 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2435 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2436 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2437 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2438 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2439 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2440 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2442 ip0->dst_address.as_u64[0] =
2443 (sr0->segments + sr0->segments_left)->as_u64[0];
2444 ip0->dst_address.as_u64[1] =
2445 (sr0->segments + sr0->segments_left)->as_u64[1];
2446 ip1->dst_address.as_u64[0] =
2447 (sr1->segments + sr1->segments_left)->as_u64[0];
2448 ip1->dst_address.as_u64[1] =
2449 (sr1->segments + sr1->segments_left)->as_u64[1];
2450 ip2->dst_address.as_u64[0] =
2451 (sr2->segments + sr2->segments_left)->as_u64[0];
2452 ip2->dst_address.as_u64[1] =
2453 (sr2->segments + sr2->segments_left)->as_u64[1];
2454 ip3->dst_address.as_u64[0] =
2455 (sr3->segments + sr3->segments_left)->as_u64[0];
2456 ip3->dst_address.as_u64[1] =
2457 (sr3->segments + sr3->segments_left)->as_u64[1];
2459 ip6_ext_header_t *ip_ext;
2460 if (ip0 + 1 == (void *) sr0)
2462 sr0->protocol = ip0->protocol;
2463 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2467 ip_ext = (void *) (ip0 + 1);
2468 sr0->protocol = ip_ext->next_hdr;
2469 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2472 if (ip1 + 1 == (void *) sr1)
2474 sr1->protocol = ip1->protocol;
2475 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2479 ip_ext = (void *) (ip2 + 1);
2480 sr2->protocol = ip_ext->next_hdr;
2481 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2484 if (ip2 + 1 == (void *) sr2)
2486 sr2->protocol = ip2->protocol;
2487 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2491 ip_ext = (void *) (ip2 + 1);
2492 sr2->protocol = ip_ext->next_hdr;
2493 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2496 if (ip3 + 1 == (void *) sr3)
2498 sr3->protocol = ip3->protocol;
2499 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2503 ip_ext = (void *) (ip3 + 1);
2504 sr3->protocol = ip_ext->next_hdr;
2505 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2510 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2512 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2514 sr_policy_rewrite_trace_t *tr =
2515 vlib_add_trace (vm, node, b0, sizeof (*tr));
2516 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2517 sizeof (tr->src.as_u8));
2518 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2519 sizeof (tr->dst.as_u8));
2522 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2524 sr_policy_rewrite_trace_t *tr =
2525 vlib_add_trace (vm, node, b1, sizeof (*tr));
2526 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2527 sizeof (tr->src.as_u8));
2528 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2529 sizeof (tr->dst.as_u8));
2532 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2534 sr_policy_rewrite_trace_t *tr =
2535 vlib_add_trace (vm, node, b2, sizeof (*tr));
2536 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2537 sizeof (tr->src.as_u8));
2538 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2539 sizeof (tr->dst.as_u8));
2542 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2544 sr_policy_rewrite_trace_t *tr =
2545 vlib_add_trace (vm, node, b3, sizeof (*tr));
2546 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2547 sizeof (tr->src.as_u8));
2548 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2549 sizeof (tr->dst.as_u8));
2553 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2554 n_left_to_next, bi0, bi1, bi2, bi3,
2555 next0, next1, next2, next3);
2558 /* Single loop for potentially the last three packets */
2559 while (n_left_from > 0 && n_left_to_next > 0)
2563 ip6_header_t *ip0 = 0;
2564 ip6_sr_header_t *sr0 = 0;
2566 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2574 n_left_to_next -= 1;
2576 b0 = vlib_get_buffer (vm, bi0);
2578 pool_elt_at_index (sm->sid_lists,
2579 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2580 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2581 vec_len (sl0->rewrite));
2583 ip0 = vlib_buffer_get_current (b0);
2585 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2587 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2588 ip6_ext_header_len (ip0 + 1));
2590 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2592 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2593 (void *) sr0 - (void *) ip0);
2594 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2595 sl0->rewrite, vec_len (sl0->rewrite));
2597 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2599 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2600 ip0->hop_limit -= 1;
2602 clib_net_to_host_u16 (ip0->payload_length) +
2603 vec_len (sl0->rewrite);
2604 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2606 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2607 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2608 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2610 ip0->dst_address.as_u64[0] =
2611 (sr0->segments + sr0->segments_left)->as_u64[0];
2612 ip0->dst_address.as_u64[1] =
2613 (sr0->segments + sr0->segments_left)->as_u64[1];
2615 if (ip0 + 1 == (void *) sr0)
2617 sr0->protocol = ip0->protocol;
2618 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2622 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2623 sr0->protocol = ip_ext->next_hdr;
2624 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2627 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2628 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2630 sr_policy_rewrite_trace_t *tr =
2631 vlib_add_trace (vm, node, b0, sizeof (*tr));
2632 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2633 sizeof (tr->src.as_u8));
2634 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2635 sizeof (tr->dst.as_u8));
2640 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2641 n_left_to_next, bi0, next0);
2644 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2647 /* Update counters */
2648 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2649 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2651 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2652 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2654 return from_frame->n_vectors;
2658 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2659 .function = sr_policy_rewrite_insert,
2660 .name = "sr-pl-rewrite-insert",
2661 .vector_size = sizeof (u32),
2662 .format_trace = format_sr_policy_rewrite_trace,
2663 .type = VLIB_NODE_TYPE_INTERNAL,
2664 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2665 .error_strings = sr_policy_rewrite_error_strings,
2666 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2668 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2669 foreach_sr_policy_rewrite_next
2676 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2679 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2680 vlib_frame_t * from_frame)
2682 ip6_sr_main_t *sm = &sr_main;
2683 u32 n_left_from, next_index, *from, *to_next;
2685 from = vlib_frame_vector_args (from_frame);
2686 n_left_from = from_frame->n_vectors;
2688 next_index = node->cached_next_index;
2690 int insert_pkts = 0, bsid_pkts = 0;
2692 while (n_left_from > 0)
2696 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2699 while (n_left_from >= 8 && n_left_to_next >= 4)
2701 u32 bi0, bi1, bi2, bi3;
2702 vlib_buffer_t *b0, *b1, *b2, *b3;
2703 u32 next0, next1, next2, next3;
2704 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2705 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2706 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2707 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2708 u16 new_l0, new_l1, new_l2, new_l3;
2710 /* Prefetch next iteration. */
2712 vlib_buffer_t *p4, *p5, *p6, *p7;
2714 p4 = vlib_get_buffer (vm, from[4]);
2715 p5 = vlib_get_buffer (vm, from[5]);
2716 p6 = vlib_get_buffer (vm, from[6]);
2717 p7 = vlib_get_buffer (vm, from[7]);
2719 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2720 vlib_prefetch_buffer_header (p4, LOAD);
2721 vlib_prefetch_buffer_header (p5, LOAD);
2722 vlib_prefetch_buffer_header (p6, LOAD);
2723 vlib_prefetch_buffer_header (p7, LOAD);
2725 clib_prefetch_store (p4->data);
2726 clib_prefetch_store (p5->data);
2727 clib_prefetch_store (p6->data);
2728 clib_prefetch_store (p7->data);
2731 to_next[0] = bi0 = from[0];
2732 to_next[1] = bi1 = from[1];
2733 to_next[2] = bi2 = from[2];
2734 to_next[3] = bi3 = from[3];
2738 n_left_to_next -= 4;
2740 b0 = vlib_get_buffer (vm, bi0);
2741 b1 = vlib_get_buffer (vm, bi1);
2742 b2 = vlib_get_buffer (vm, bi2);
2743 b3 = vlib_get_buffer (vm, bi3);
2746 pool_elt_at_index (sm->sid_lists,
2747 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2749 pool_elt_at_index (sm->sid_lists,
2750 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2752 pool_elt_at_index (sm->sid_lists,
2753 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2755 pool_elt_at_index (sm->sid_lists,
2756 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2757 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2758 vec_len (sl0->rewrite_bsid));
2759 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2760 vec_len (sl1->rewrite_bsid));
2761 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2762 vec_len (sl2->rewrite_bsid));
2763 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2764 vec_len (sl3->rewrite_bsid));
2766 ip0 = vlib_buffer_get_current (b0);
2767 ip1 = vlib_buffer_get_current (b1);
2768 ip2 = vlib_buffer_get_current (b2);
2769 ip3 = vlib_buffer_get_current (b3);
2771 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2773 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2774 ip6_ext_header_len (ip0 + 1));
2776 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2778 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2780 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2781 ip6_ext_header_len (ip1 + 1));
2783 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2785 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2787 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2788 ip6_ext_header_len (ip2 + 1));
2790 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2792 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2794 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2795 ip6_ext_header_len (ip3 + 1));
2797 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2799 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2800 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2801 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2802 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2803 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2804 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2805 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2806 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2808 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2809 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2810 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2811 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2812 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2813 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2814 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2815 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2817 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2818 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2819 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2820 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2822 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2823 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2824 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2825 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2827 ip0->hop_limit -= 1;
2828 ip1->hop_limit -= 1;
2829 ip2->hop_limit -= 1;
2830 ip3->hop_limit -= 1;
2833 clib_net_to_host_u16 (ip0->payload_length) +
2834 vec_len (sl0->rewrite_bsid);
2836 clib_net_to_host_u16 (ip1->payload_length) +
2837 vec_len (sl1->rewrite_bsid);
2839 clib_net_to_host_u16 (ip2->payload_length) +
2840 vec_len (sl2->rewrite_bsid);
2842 clib_net_to_host_u16 (ip3->payload_length) +
2843 vec_len (sl3->rewrite_bsid);
2845 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2846 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2847 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2848 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2850 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2851 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2852 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2853 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2855 ip0->dst_address.as_u64[0] =
2856 (sr0->segments + sr0->segments_left)->as_u64[0];
2857 ip0->dst_address.as_u64[1] =
2858 (sr0->segments + sr0->segments_left)->as_u64[1];
2859 ip1->dst_address.as_u64[0] =
2860 (sr1->segments + sr1->segments_left)->as_u64[0];
2861 ip1->dst_address.as_u64[1] =
2862 (sr1->segments + sr1->segments_left)->as_u64[1];
2863 ip2->dst_address.as_u64[0] =
2864 (sr2->segments + sr2->segments_left)->as_u64[0];
2865 ip2->dst_address.as_u64[1] =
2866 (sr2->segments + sr2->segments_left)->as_u64[1];
2867 ip3->dst_address.as_u64[0] =
2868 (sr3->segments + sr3->segments_left)->as_u64[0];
2869 ip3->dst_address.as_u64[1] =
2870 (sr3->segments + sr3->segments_left)->as_u64[1];
2872 ip6_ext_header_t *ip_ext;
2873 if (ip0 + 1 == (void *) sr0)
2875 sr0->protocol = ip0->protocol;
2876 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2880 ip_ext = (void *) (ip0 + 1);
2881 sr0->protocol = ip_ext->next_hdr;
2882 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2885 if (ip1 + 1 == (void *) sr1)
2887 sr1->protocol = ip1->protocol;
2888 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2892 ip_ext = (void *) (ip2 + 1);
2893 sr2->protocol = ip_ext->next_hdr;
2894 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2897 if (ip2 + 1 == (void *) sr2)
2899 sr2->protocol = ip2->protocol;
2900 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2904 ip_ext = (void *) (ip2 + 1);
2905 sr2->protocol = ip_ext->next_hdr;
2906 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2909 if (ip3 + 1 == (void *) sr3)
2911 sr3->protocol = ip3->protocol;
2912 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2916 ip_ext = (void *) (ip3 + 1);
2917 sr3->protocol = ip_ext->next_hdr;
2918 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2923 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2925 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2927 sr_policy_rewrite_trace_t *tr =
2928 vlib_add_trace (vm, node, b0, sizeof (*tr));
2929 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2930 sizeof (tr->src.as_u8));
2931 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2932 sizeof (tr->dst.as_u8));
2935 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2937 sr_policy_rewrite_trace_t *tr =
2938 vlib_add_trace (vm, node, b1, sizeof (*tr));
2939 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2940 sizeof (tr->src.as_u8));
2941 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2942 sizeof (tr->dst.as_u8));
2945 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2947 sr_policy_rewrite_trace_t *tr =
2948 vlib_add_trace (vm, node, b2, sizeof (*tr));
2949 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2950 sizeof (tr->src.as_u8));
2951 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2952 sizeof (tr->dst.as_u8));
2955 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2957 sr_policy_rewrite_trace_t *tr =
2958 vlib_add_trace (vm, node, b3, sizeof (*tr));
2959 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2960 sizeof (tr->src.as_u8));
2961 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2962 sizeof (tr->dst.as_u8));
2966 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2967 n_left_to_next, bi0, bi1, bi2, bi3,
2968 next0, next1, next2, next3);
2971 /* Single loop for potentially the last three packets */
2972 while (n_left_from > 0 && n_left_to_next > 0)
2976 ip6_header_t *ip0 = 0;
2977 ip6_sr_header_t *sr0 = 0;
2979 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2987 n_left_to_next -= 1;
2989 b0 = vlib_get_buffer (vm, bi0);
2991 pool_elt_at_index (sm->sid_lists,
2992 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2993 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2994 vec_len (sl0->rewrite_bsid));
2996 ip0 = vlib_buffer_get_current (b0);
2998 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3000 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3001 ip6_ext_header_len (ip0 + 1));
3003 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3005 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3006 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3007 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3008 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3010 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3012 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3013 ip0->hop_limit -= 1;
3015 clib_net_to_host_u16 (ip0->payload_length) +
3016 vec_len (sl0->rewrite_bsid);
3017 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3019 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3021 ip0->dst_address.as_u64[0] =
3022 (sr0->segments + sr0->segments_left)->as_u64[0];
3023 ip0->dst_address.as_u64[1] =
3024 (sr0->segments + sr0->segments_left)->as_u64[1];
3026 if (ip0 + 1 == (void *) sr0)
3028 sr0->protocol = ip0->protocol;
3029 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3033 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3034 sr0->protocol = ip_ext->next_hdr;
3035 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3038 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3039 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3041 sr_policy_rewrite_trace_t *tr =
3042 vlib_add_trace (vm, node, b0, sizeof (*tr));
3043 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3044 sizeof (tr->src.as_u8));
3045 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3046 sizeof (tr->dst.as_u8));
3051 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3052 n_left_to_next, bi0, next0);
3055 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3058 /* Update counters */
3059 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3060 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3062 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3063 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3065 return from_frame->n_vectors;
3069 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3070 .function = sr_policy_rewrite_b_insert,
3071 .name = "sr-pl-rewrite-b-insert",
3072 .vector_size = sizeof (u32),
3073 .format_trace = format_sr_policy_rewrite_trace,
3074 .type = VLIB_NODE_TYPE_INTERNAL,
3075 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3076 .error_strings = sr_policy_rewrite_error_strings,
3077 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3079 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3080 foreach_sr_policy_rewrite_next
3087 * @brief Function BSID encapsulation
3089 static_always_inline void
3090 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
3093 ip6_sr_header_t * sr0, u32 * next0)
3095 ip6_address_t *new_dst0;
3097 if (PREDICT_FALSE (!sr0))
3098 goto error_bsid_encaps;
3100 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3102 if (PREDICT_TRUE (sr0->segments_left != 0))
3104 sr0->segments_left -= 1;
3105 new_dst0 = (ip6_address_t *) (sr0->segments);
3106 new_dst0 += sr0->segments_left;
3107 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3108 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3114 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3115 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3119 * @brief Graph node for applying a SR policy BSID - Encapsulation
3122 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3123 vlib_frame_t * from_frame)
3125 ip6_sr_main_t *sm = &sr_main;
3126 u32 n_left_from, next_index, *from, *to_next;
3128 from = vlib_frame_vector_args (from_frame);
3129 n_left_from = from_frame->n_vectors;
3131 next_index = node->cached_next_index;
3133 int encap_pkts = 0, bsid_pkts = 0;
3135 while (n_left_from > 0)
3139 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3142 while (n_left_from >= 8 && n_left_to_next >= 4)
3144 u32 bi0, bi1, bi2, bi3;
3145 vlib_buffer_t *b0, *b1, *b2, *b3;
3146 u32 next0, next1, next2, next3;
3147 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3148 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3149 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3150 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3151 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3153 /* Prefetch next iteration. */
3155 vlib_buffer_t *p4, *p5, *p6, *p7;
3157 p4 = vlib_get_buffer (vm, from[4]);
3158 p5 = vlib_get_buffer (vm, from[5]);
3159 p6 = vlib_get_buffer (vm, from[6]);
3160 p7 = vlib_get_buffer (vm, from[7]);
3162 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3163 vlib_prefetch_buffer_header (p4, LOAD);
3164 vlib_prefetch_buffer_header (p5, LOAD);
3165 vlib_prefetch_buffer_header (p6, LOAD);
3166 vlib_prefetch_buffer_header (p7, LOAD);
3168 clib_prefetch_store (p4->data);
3169 clib_prefetch_store (p5->data);
3170 clib_prefetch_store (p6->data);
3171 clib_prefetch_store (p7->data);
3174 to_next[0] = bi0 = from[0];
3175 to_next[1] = bi1 = from[1];
3176 to_next[2] = bi2 = from[2];
3177 to_next[3] = bi3 = from[3];
3181 n_left_to_next -= 4;
3183 b0 = vlib_get_buffer (vm, bi0);
3184 b1 = vlib_get_buffer (vm, bi1);
3185 b2 = vlib_get_buffer (vm, bi2);
3186 b3 = vlib_get_buffer (vm, bi3);
3189 pool_elt_at_index (sm->sid_lists,
3190 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3192 pool_elt_at_index (sm->sid_lists,
3193 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3195 pool_elt_at_index (sm->sid_lists,
3196 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3198 pool_elt_at_index (sm->sid_lists,
3199 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3200 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3201 vec_len (sl0->rewrite));
3202 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3203 vec_len (sl1->rewrite));
3204 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3205 vec_len (sl2->rewrite));
3206 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3207 vec_len (sl3->rewrite));
3209 ip0_encap = vlib_buffer_get_current (b0);
3210 ip1_encap = vlib_buffer_get_current (b1);
3211 ip2_encap = vlib_buffer_get_current (b2);
3212 ip3_encap = vlib_buffer_get_current (b3);
3215 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3218 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3221 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3224 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3227 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3228 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
3229 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
3230 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
3232 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3233 sl0->rewrite, vec_len (sl0->rewrite));
3234 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3235 sl1->rewrite, vec_len (sl1->rewrite));
3236 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3237 sl2->rewrite, vec_len (sl2->rewrite));
3238 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3239 sl3->rewrite, vec_len (sl3->rewrite));
3241 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3242 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3243 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3244 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3246 ip0 = vlib_buffer_get_current (b0);
3247 ip1 = vlib_buffer_get_current (b1);
3248 ip2 = vlib_buffer_get_current (b2);
3249 ip3 = vlib_buffer_get_current (b3);
3251 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3252 encaps_processing_v6 (node, b1, ip1, ip1_encap);
3253 encaps_processing_v6 (node, b2, ip2, ip2_encap);
3254 encaps_processing_v6 (node, b3, ip3, ip3_encap);
3256 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3258 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3260 sr_policy_rewrite_trace_t *tr =
3261 vlib_add_trace (vm, node, b0, sizeof (*tr));
3262 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3263 sizeof (tr->src.as_u8));
3264 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3265 sizeof (tr->dst.as_u8));
3268 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3270 sr_policy_rewrite_trace_t *tr =
3271 vlib_add_trace (vm, node, b1, sizeof (*tr));
3272 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3273 sizeof (tr->src.as_u8));
3274 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3275 sizeof (tr->dst.as_u8));
3278 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3280 sr_policy_rewrite_trace_t *tr =
3281 vlib_add_trace (vm, node, b2, sizeof (*tr));
3282 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3283 sizeof (tr->src.as_u8));
3284 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3285 sizeof (tr->dst.as_u8));
3288 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3290 sr_policy_rewrite_trace_t *tr =
3291 vlib_add_trace (vm, node, b3, sizeof (*tr));
3292 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3293 sizeof (tr->src.as_u8));
3294 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3295 sizeof (tr->dst.as_u8));
3300 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3301 n_left_to_next, bi0, bi1, bi2, bi3,
3302 next0, next1, next2, next3);
3305 /* Single loop for potentially the last three packets */
3306 while (n_left_from > 0 && n_left_to_next > 0)
3310 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3311 ip6_sr_header_t *sr0;
3313 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3320 n_left_to_next -= 1;
3321 b0 = vlib_get_buffer (vm, bi0);
3324 pool_elt_at_index (sm->sid_lists,
3325 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3326 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3327 vec_len (sl0->rewrite));
3329 ip0_encap = vlib_buffer_get_current (b0);
3331 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3333 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3335 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3336 sl0->rewrite, vec_len (sl0->rewrite));
3337 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3339 ip0 = vlib_buffer_get_current (b0);
3341 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3343 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3344 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3346 sr_policy_rewrite_trace_t *tr =
3347 vlib_add_trace (vm, node, b0, sizeof (*tr));
3348 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3349 sizeof (tr->src.as_u8));
3350 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3351 sizeof (tr->dst.as_u8));
3355 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3356 n_left_to_next, bi0, next0);
3359 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3362 /* Update counters */
3363 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3364 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3366 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3367 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3370 return from_frame->n_vectors;
3374 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3375 .function = sr_policy_rewrite_b_encaps,
3376 .name = "sr-pl-rewrite-b-encaps",
3377 .vector_size = sizeof (u32),
3378 .format_trace = format_sr_policy_rewrite_trace,
3379 .type = VLIB_NODE_TYPE_INTERNAL,
3380 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3381 .error_strings = sr_policy_rewrite_error_strings,
3382 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3384 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3385 foreach_sr_policy_rewrite_next
3391 /*************************** SR Policy plugins ******************************/
3393 * @brief SR Policy plugin registry
3396 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3397 u8 * keyword_str, u8 * def_str,
3398 u8 * params_str, u8 prefix_length,
3400 format_function_t * ls_format,
3401 unformat_function_t * ls_unformat,
3402 sr_p_plugin_callback_t * creation_fn,
3403 sr_p_plugin_callback_t * removal_fn)
3405 ip6_sr_main_t *sm = &sr_main;
3408 sr_policy_fn_registration_t *plugin;
3410 /* Did this function exist? If so update it */
3411 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3414 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3416 /* Else create a new one and set hash key */
3419 pool_get (sm->policy_plugin_functions, plugin);
3420 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3421 plugin - sm->policy_plugin_functions);
3424 clib_memset (plugin, 0, sizeof (*plugin));
3426 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3427 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3428 plugin->prefix_length = prefix_length;
3429 plugin->ls_format = ls_format;
3430 plugin->ls_unformat = ls_unformat;
3431 plugin->creation = creation_fn;
3432 plugin->removal = removal_fn;
3433 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3434 plugin->function_name = format (0, "%s%c", fn_name, 0);
3435 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3436 plugin->def_str = format (0, "%s%c", def_str, 0);
3437 plugin->params_str = format (0, "%s%c", params_str, 0);
3439 return plugin->sr_policy_function_number;
3443 * @brief CLI function to 'show' all available SR LocalSID behaviors
3445 static clib_error_t *
3446 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3447 unformat_input_t * input,
3448 vlib_cli_command_t * cmd)
3450 ip6_sr_main_t *sm = &sr_main;
3451 sr_policy_fn_registration_t *plugin;
3452 sr_policy_fn_registration_t **plugins_vec = 0;
3455 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3458 pool_foreach (plugin, sm->policy_plugin_functions)
3459 { vec_add1 (plugins_vec, plugin); }
3462 vlib_cli_output (vm, "Plugin behaviors:\n");
3463 for (i = 0; i < vec_len (plugins_vec); i++)
3465 plugin = plugins_vec[i];
3466 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3468 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3474 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3475 .path = "show sr policy behaviors",
3476 .short_help = "show sr policy behaviors",
3477 .function = show_sr_policy_behaviors_command_fn,
3481 /*************************** SR Segment Lists DPOs ****************************/
3483 format_sr_segment_list_dpo (u8 * s, va_list * args)
3485 ip6_sr_main_t *sm = &sr_main;
3486 ip6_address_t *addr;
3489 index_t index = va_arg (*args, index_t);
3490 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3491 s = format (s, "SR: Segment List index:[%d]", index);
3492 s = format (s, "\n\tSegments:");
3494 sl = pool_elt_at_index (sm->sid_lists, index);
3496 s = format (s, "< ");
3497 vec_foreach (addr, sl->segments)
3499 s = format (s, "%U, ", format_ip6_address, addr);
3501 s = format (s, "\b\b > - ");
3502 s = format (s, "Weight: %u", sl->weight);
3507 const static dpo_vft_t sr_policy_rewrite_vft = {
3508 .dv_lock = sr_dpo_lock,
3509 .dv_unlock = sr_dpo_unlock,
3510 .dv_format = format_sr_segment_list_dpo,
3513 const static char *const sr_pr_encaps_ip6_nodes[] = {
3514 "sr-pl-rewrite-encaps",
3518 const static char *const sr_pr_encaps_ip4_nodes[] = {
3519 "sr-pl-rewrite-encaps-v4",
3523 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3524 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3525 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3528 const static char *const sr_pr_insert_ip6_nodes[] = {
3529 "sr-pl-rewrite-insert",
3533 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3534 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3537 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3538 "sr-pl-rewrite-b-insert",
3542 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3543 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3546 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3547 "sr-pl-rewrite-b-encaps",
3551 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3552 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3555 /********************* SR Policy Rewrite initialization ***********************/
3557 * @brief SR Policy Rewrite initialization
3560 sr_policy_rewrite_init (vlib_main_t * vm)
3562 ip6_sr_main_t *sm = &sr_main;
3564 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3565 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3566 sizeof (ip6_address_t));
3568 /* Init SR VPO DPOs type */
3569 sr_pr_encaps_dpo_type =
3570 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3572 sr_pr_insert_dpo_type =
3573 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3575 sr_pr_bsid_encaps_dpo_type =
3576 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3578 sr_pr_bsid_insert_dpo_type =
3579 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3581 /* Register the L2 encaps node used in HW redirect */
3582 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3584 sm->fib_table_ip6 = (u32) ~ 0;
3585 sm->fib_table_ip4 = (u32) ~ 0;
3590 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3594 * fd.io coding-style-patch-verification: ON
3597 * eval: (c-set-style "gnu")