2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropriate VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/srv6/sr.h>
44 #include <vnet/ip/ip4_inlines.h>
45 #include <vnet/ip/ip6_inlines.h>
46 #include <vnet/srv6/sr_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
110 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
112 /******************* SR rewrite set encaps IPv6 source addr *******************/
113 /* Note: This is temporal. We don't know whether to follow this path or
114 take the ip address of a loopback interface or even the OIF */
117 sr_set_source (ip6_address_t * address)
119 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
123 sr_get_encaps_source ()
125 return &sr_pr_encaps_src;
128 static clib_error_t *
129 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
130 vlib_cli_command_t * cmd)
132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
135 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
138 return clib_error_return (0, "No address specified");
140 return clib_error_return (0, "No address specified");
144 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
145 .path = "set sr encaps source",
146 .short_help = "set sr encaps source addr <ip6_addr>",
147 .function = set_sr_src_command_fn,
151 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
154 sr_set_hop_limit (u8 hop_limit)
156 sr_pr_encaps_hop_limit = hop_limit;
160 sr_get_hop_limit (void)
162 return sr_pr_encaps_hop_limit;
165 static clib_error_t *
166 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
167 vlib_cli_command_t * cmd)
169 int hop_limit = sr_get_hop_limit ();
171 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
172 return clib_error_return (0, "No value specified");
173 if (!unformat (input, "%d", &hop_limit))
174 return clib_error_return (0, "Invalid value");
175 if (hop_limit <= 0 || hop_limit > 255)
176 return clib_error_return (0, "Value out of range [1-255]");
177 sr_pr_encaps_hop_limit = (u8) hop_limit;
182 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
183 .path = "set sr encaps hop-limit",
184 .short_help = "set sr encaps hop-limit <value>",
185 .function = set_sr_hop_limit_command_fn,
189 /*********************** SR rewrite string computation ************************/
191 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
193 * @param sl is a vector of IPv6 addresses composing the Segment List
195 * @return precomputed rewrite string for encapsulation
198 compute_rewrite_encaps (ip6_address_t *sl, u8 type)
201 ip6_sr_header_t *srh;
202 ip6_sr_pt_tlv_t *srh_pt_tlv;
203 ip6_address_t *addrp, *this_address;
204 u32 header_length = 0;
208 header_length += IPv6_DEFAULT_HEADER_LENGTH;
209 if (type == SR_POLICY_TYPE_TEF)
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += vec_len (sl) * sizeof (ip6_address_t);
213 header_length += sizeof (ip6_sr_pt_tlv_t);
215 else if (vec_len (sl) > 1)
217 header_length += sizeof (ip6_sr_header_t);
218 header_length += vec_len (sl) * sizeof (ip6_address_t);
221 vec_validate (rs, header_length - 1);
223 iph = (ip6_header_t *) rs;
224 iph->ip_version_traffic_class_and_flow_label =
225 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
226 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
227 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
228 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
229 iph->protocol = IP_PROTOCOL_IPV6;
230 iph->hop_limit = sr_pr_encaps_hop_limit;
232 if (type == SR_POLICY_TYPE_TEF)
234 srh = (ip6_sr_header_t *) (iph + 1);
235 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
236 srh->protocol = IP_PROTOCOL_IPV6;
237 srh->type = ROUTING_HEADER_TYPE_SR;
240 srh->segments_left = vec_len (sl) - 1;
241 srh->last_entry = vec_len (sl) - 1;
243 ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
244 sizeof (ip6_sr_pt_tlv_t)) /
247 addrp = srh->segments + vec_len (sl) - 1;
248 vec_foreach (this_address, sl)
250 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
251 sizeof (ip6_address_t));
254 srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
255 srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
256 srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
258 else if (vec_len (sl) > 1)
260 srh = (ip6_sr_header_t *) (iph + 1);
261 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
262 srh->protocol = IP_PROTOCOL_IPV6;
263 srh->type = ROUTING_HEADER_TYPE_SR;
264 srh->segments_left = vec_len (sl) - 1;
265 srh->last_entry = vec_len (sl) - 1;
266 srh->length = ((sizeof (ip6_sr_header_t) +
267 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
270 addrp = srh->segments + vec_len (sl) - 1;
271 vec_foreach (this_address, sl)
273 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
274 sizeof (ip6_address_t));
278 iph->dst_address.as_u64[0] = sl->as_u64[0];
279 iph->dst_address.as_u64[1] = sl->as_u64[1];
284 * @brief SR rewrite string computation for SRH insertion (inline)
286 * @param sl is a vector of IPv6 addresses composing the Segment List
288 * @return precomputed rewrite string for SRH insertion
291 compute_rewrite_insert (ip6_address_t *sl, u8 type)
293 ip6_sr_header_t *srh;
294 ip6_address_t *addrp, *this_address;
295 u32 header_length = 0;
299 header_length += sizeof (ip6_sr_header_t);
300 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
302 vec_validate (rs, header_length - 1);
304 srh = (ip6_sr_header_t *) rs;
305 srh->type = ROUTING_HEADER_TYPE_SR;
306 srh->segments_left = vec_len (sl);
307 srh->last_entry = vec_len (sl);
308 srh->length = ((sizeof (ip6_sr_header_t) +
309 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
312 addrp = srh->segments + vec_len (sl);
313 vec_foreach (this_address, sl)
315 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
316 sizeof (ip6_address_t));
323 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
325 * @param sl is a vector of IPv6 addresses composing the Segment List
327 * @return precomputed rewrite string for SRH insertion with BSID
330 compute_rewrite_bsid (ip6_address_t * sl)
332 ip6_sr_header_t *srh;
333 ip6_address_t *addrp, *this_address;
334 u32 header_length = 0;
338 header_length += sizeof (ip6_sr_header_t);
339 header_length += vec_len (sl) * sizeof (ip6_address_t);
341 vec_validate (rs, header_length - 1);
343 srh = (ip6_sr_header_t *) rs;
344 srh->type = ROUTING_HEADER_TYPE_SR;
345 srh->segments_left = vec_len (sl) - 1;
346 srh->last_entry = vec_len (sl) - 1;
347 srh->length = ((sizeof (ip6_sr_header_t) +
348 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
351 addrp = srh->segments + vec_len (sl) - 1;
352 vec_foreach (this_address, sl)
354 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
355 sizeof (ip6_address_t));
361 /*************************** SR LB helper functions **************************/
363 * @brief Creates a Segment List and adds it to an SR policy
365 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
366 * not necessarily unique. Hence there might be two Segment List within the
367 * same SR Policy with exactly the same segments and same weight.
369 * @param sr_policy is the SR policy where the SL will be added
370 * @param sl is a vector of IPv6 addresses composing the Segment List
371 * @param weight is the weight of the SegmentList (for load-balancing purposes)
372 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
374 * @return pointer to the just created segment list
376 static inline ip6_sr_sl_t *
377 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
380 ip6_sr_main_t *sm = &sr_main;
381 ip6_sr_sl_t *segment_list;
382 sr_policy_fn_registration_t *plugin = 0;
384 pool_get (sm->sid_lists, segment_list);
385 clib_memset (segment_list, 0, sizeof (*segment_list));
387 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
389 /* Fill in segment list */
390 segment_list->weight =
391 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
393 segment_list->segments = vec_dup (sl);
394 segment_list->policy_type = sr_policy->type;
396 segment_list->egress_fib_table =
397 ip6_fib_index_from_table_id (sr_policy->fib_table);
401 segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type);
402 segment_list->rewrite_bsid = segment_list->rewrite;
406 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
407 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
410 if (sr_policy->plugin)
413 pool_elt_at_index (sm->policy_plugin_functions,
414 sr_policy->plugin - SR_BEHAVIOR_LAST);
416 segment_list->plugin = sr_policy->plugin;
417 segment_list->plugin_mem = sr_policy->plugin_mem;
419 plugin->creation (sr_policy);
423 dpo_reset (&segment_list->bsid_dpo);
424 dpo_reset (&segment_list->ip6_dpo);
425 dpo_reset (&segment_list->ip4_dpo);
429 if (!sr_policy->plugin)
431 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
432 DPO_PROTO_IP6, segment_list - sm->sid_lists);
433 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
434 DPO_PROTO_IP4, segment_list - sm->sid_lists);
435 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
436 DPO_PROTO_IP6, segment_list - sm->sid_lists);
440 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
441 segment_list - sm->sid_lists);
442 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
443 segment_list - sm->sid_lists);
444 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
445 segment_list - sm->sid_lists);
450 if (!sr_policy->plugin)
452 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
453 DPO_PROTO_IP6, segment_list - sm->sid_lists);
454 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
455 DPO_PROTO_IP6, segment_list - sm->sid_lists);
459 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
460 segment_list - sm->sid_lists);
461 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
462 segment_list - sm->sid_lists);
470 * @brief Updates the Load-Balancer after an SR Policy change
472 * @param sr_policy is the modified SR Policy
475 update_lb (ip6_sr_policy_t * sr_policy)
477 flow_hash_config_t fhc;
479 ip6_sr_sl_t *segment_list;
480 ip6_sr_main_t *sm = &sr_main;
481 load_balance_path_t path;
482 path.path_index = FIB_NODE_INDEX_INVALID;
483 load_balance_path_t *ip4_path_vector = 0;
484 load_balance_path_t *ip6_path_vector = 0;
485 load_balance_path_t *b_path_vector = 0;
487 /* In case LB does not exist, create it */
488 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
491 .fp_proto = FIB_PROTOCOL_IP6,
494 .ip6 = sr_policy->bsid,
498 /* Add FIB entry for BSID */
499 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
502 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
503 load_balance_create (0, DPO_PROTO_IP6, fhc));
505 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
506 load_balance_create (0, DPO_PROTO_IP6, fhc));
508 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
509 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
510 sr_policy->fib_table),
512 FIB_ENTRY_FLAG_EXCLUSIVE,
513 &sr_policy->bsid_dpo);
515 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
518 FIB_ENTRY_FLAG_EXCLUSIVE,
519 &sr_policy->ip6_dpo);
521 if (sr_policy->is_encap)
523 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
524 load_balance_create (0, DPO_PROTO_IP4, fhc));
526 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
529 FIB_ENTRY_FLAG_EXCLUSIVE,
530 &sr_policy->ip4_dpo);
535 /* Create the LB path vector */
536 vec_foreach (sl_index, sr_policy->segments_lists)
538 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
539 path.path_dpo = segment_list->bsid_dpo;
540 path.path_weight = segment_list->weight;
541 vec_add1 (b_path_vector, path);
542 path.path_dpo = segment_list->ip6_dpo;
543 vec_add1 (ip6_path_vector, path);
544 if (sr_policy->is_encap)
546 path.path_dpo = segment_list->ip4_dpo;
547 vec_add1 (ip4_path_vector, path);
551 /* Update LB multipath */
552 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
553 LOAD_BALANCE_FLAG_NONE);
554 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
555 LOAD_BALANCE_FLAG_NONE);
556 if (sr_policy->is_encap)
557 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
558 LOAD_BALANCE_FLAG_NONE);
561 vec_free (b_path_vector);
562 vec_free (ip6_path_vector);
563 vec_free (ip4_path_vector);
567 * @brief Updates the Replicate DPO after an SR Policy change
569 * @param sr_policy is the modified SR Policy (type spray)
572 update_replicate (ip6_sr_policy_t * sr_policy)
575 ip6_sr_sl_t *segment_list;
576 ip6_sr_main_t *sm = &sr_main;
577 load_balance_path_t path;
578 path.path_index = FIB_NODE_INDEX_INVALID;
579 load_balance_path_t *b_path_vector = 0;
580 load_balance_path_t *ip6_path_vector = 0;
581 load_balance_path_t *ip4_path_vector = 0;
583 /* In case LB does not exist, create it */
584 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
586 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
587 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
589 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
590 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
592 /* Update FIB entry's DPO to point to SR without LB */
594 .fp_proto = FIB_PROTOCOL_IP6,
597 .ip6 = sr_policy->bsid,
600 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
601 sr_policy->fib_table),
603 FIB_ENTRY_FLAG_EXCLUSIVE,
604 &sr_policy->bsid_dpo);
606 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
609 FIB_ENTRY_FLAG_EXCLUSIVE,
610 &sr_policy->ip6_dpo);
612 if (sr_policy->is_encap)
614 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
615 replicate_create (0, DPO_PROTO_IP4));
617 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
620 FIB_ENTRY_FLAG_EXCLUSIVE,
621 &sr_policy->ip4_dpo);
626 /* Create the replicate path vector */
627 path.path_weight = 1;
628 vec_foreach (sl_index, sr_policy->segments_lists)
630 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
631 path.path_dpo = segment_list->bsid_dpo;
632 vec_add1 (b_path_vector, path);
633 path.path_dpo = segment_list->ip6_dpo;
634 vec_add1 (ip6_path_vector, path);
635 if (sr_policy->is_encap)
637 path.path_dpo = segment_list->ip4_dpo;
638 vec_add1 (ip4_path_vector, path);
642 /* Update replicate multipath */
643 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
644 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
645 if (sr_policy->is_encap)
646 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
649 /******************************* SR rewrite API *******************************/
650 /* Three functions for handling sr policies:
654 * All of them are API. CLI function on sr_policy_command_fn */
657 * @brief Create a new SR policy
659 * @param bsid is the bindingSID of the SR Policy
660 * @param segments is a vector of IPv6 address composing the segment list
661 * @param weight is the weight of the sid list. optional.
662 * @param behavior is the behavior of the SR policy. (default//spray)
663 * @param fib_table is the VRF where to install the FIB entry for the BSID
664 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
666 * @return 0 if correct, else error
669 sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight,
670 u8 type, u32 fib_table, u8 is_encap, u16 plugin,
673 ip6_sr_main_t *sm = &sr_main;
674 ip6_sr_policy_t *sr_policy = 0;
677 /* Search for existing keys (BSID) */
678 p = mhash_get (&sm->sr_policies_index_hash, bsid);
681 /* Add SR policy that already exists; complain */
685 /* Search collision in FIB entries */
686 /* Explanation: It might be possible that some other entity has already
687 * created a route for the BSID. This in theory is impossible, but in
688 * practise we could see it. Assert it and scream if needed */
690 .fp_proto = FIB_PROTOCOL_IP6,
697 /* Lookup the FIB index associated to the table selected */
698 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
699 (fib_table != (u32) ~ 0 ? fib_table : 0));
703 /* Lookup whether there exists an entry for the BSID */
704 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
705 if (FIB_NODE_INDEX_INVALID != fei)
706 return -12; //There is an entry for such lookup
708 /* Add an SR policy object */
709 pool_get (sm->sr_policies, sr_policy);
710 clib_memset (sr_policy, 0, sizeof (*sr_policy));
711 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
712 sr_policy->type = type;
713 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
714 sr_policy->is_encap = is_encap;
718 sr_policy->plugin = plugin;
719 sr_policy->plugin_mem = ls_plugin_mem;
723 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
726 /* Create a segment list and add the index to the SR policy */
727 create_sl (sr_policy, segments, weight, is_encap);
729 /* If FIB doesnt exist, create them */
730 if (sm->fib_table_ip6 == (u32) ~ 0)
732 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
734 "SRv6 steering of IP6 prefixes through BSIDs");
735 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
737 "SRv6 steering of IP4 prefixes through BSIDs");
740 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
741 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
742 sr_policy->type == SR_POLICY_TYPE_TEF)
743 update_lb (sr_policy);
744 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
745 update_replicate (sr_policy);
750 * @brief Delete a SR policy
752 * @param bsid is the bindingSID of the SR Policy
753 * @param index is the index of the SR policy
755 * @return 0 if correct, else error
758 sr_policy_del (ip6_address_t * bsid, u32 index)
760 ip6_sr_main_t *sm = &sr_main;
761 ip6_sr_policy_t *sr_policy = 0;
762 ip6_sr_sl_t *segment_list;
768 p = mhash_get (&sm->sr_policies_index_hash, bsid);
770 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
776 sr_policy = pool_elt_at_index (sm->sr_policies, index);
779 /* Remove BindingSID FIB entry */
781 .fp_proto = FIB_PROTOCOL_IP6,
784 .ip6 = sr_policy->bsid,
789 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
790 sr_policy->fib_table),
791 &pfx, FIB_SOURCE_SR);
793 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
795 if (sr_policy->is_encap)
796 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
798 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
800 dpo_reset (&sr_policy->bsid_dpo);
801 dpo_reset (&sr_policy->ip4_dpo);
802 dpo_reset (&sr_policy->ip6_dpo);
805 /* Clean SID Lists */
806 vec_foreach (sl_index, sr_policy->segments_lists)
808 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
809 vec_free (segment_list->segments);
810 vec_free (segment_list->rewrite);
811 if (!sr_policy->is_encap)
812 vec_free (segment_list->rewrite_bsid);
813 pool_put_index (sm->sid_lists, *sl_index);
816 if (sr_policy->plugin)
818 sr_policy_fn_registration_t *plugin = 0;
821 pool_elt_at_index (sm->policy_plugin_functions,
822 sr_policy->plugin - SR_BEHAVIOR_LAST);
824 plugin->removal (sr_policy);
825 sr_policy->plugin = 0;
826 sr_policy->plugin_mem = NULL;
829 /* Remove SR policy entry */
830 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
831 pool_put (sm->sr_policies, sr_policy);
833 /* If FIB empty unlock it */
834 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
836 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
837 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
838 sm->fib_table_ip6 = (u32) ~ 0;
839 sm->fib_table_ip4 = (u32) ~ 0;
846 * @brief Modify an existing SR policy
848 * The possible modifications are adding a new Segment List, modifying an
849 * existing Segment List (modify the weight only) and delete a given
850 * Segment List from the SR Policy.
852 * @param bsid is the bindingSID of the SR Policy
853 * @param index is the index of the SR policy
854 * @param fib_table is the VRF where to install the FIB entry for the BSID
855 * @param operation is the operation to perform (among the top ones)
856 * @param segments is a vector of IPv6 address composing the segment list
857 * @param sl_index is the index of the Segment List to modify/delete
858 * @param weight is the weight of the sid list. optional.
859 * @param is_encap Mode. Encapsulation or SRH insertion.
861 * @return 0 if correct, else error
864 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
865 u8 operation, ip6_address_t * segments, u32 sl_index,
868 ip6_sr_main_t *sm = &sr_main;
869 ip6_sr_policy_t *sr_policy = 0;
870 ip6_sr_sl_t *segment_list;
871 u32 *sl_index_iterate;
876 p = mhash_get (&sm->sr_policies_index_hash, bsid);
878 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
884 sr_policy = pool_elt_at_index (sm->sr_policies, index);
887 if (operation == 1) /* Add SR List to an existing SR policy */
889 /* Create the new SL */
891 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
893 /* Create a new LB DPO */
894 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
895 update_lb (sr_policy);
896 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
897 update_replicate (sr_policy);
899 else if (operation == 2) /* Delete SR List from an existing SR policy */
901 /* Check that currently there are more than one SID list */
902 if (vec_len (sr_policy->segments_lists) == 1)
905 /* Check that the SR list does exist and is assigned to the sr policy */
906 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
907 if (*sl_index_iterate == sl_index)
910 if (*sl_index_iterate != sl_index)
913 /* Remove the lucky SR list that is being kicked out */
914 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
915 vec_free (segment_list->segments);
916 vec_free (segment_list->rewrite);
917 if (!sr_policy->is_encap)
918 vec_free (segment_list->rewrite_bsid);
919 pool_put_index (sm->sid_lists, sl_index);
920 vec_del1 (sr_policy->segments_lists,
921 sl_index_iterate - sr_policy->segments_lists);
923 /* Create a new LB DPO */
924 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
925 update_lb (sr_policy);
926 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
927 update_replicate (sr_policy);
929 else if (operation == 3) /* Modify the weight of an existing SR List */
931 /* Find the corresponding SL */
932 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
933 if (*sl_index_iterate == sl_index)
936 if (*sl_index_iterate != sl_index)
939 /* Change the weight */
940 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
941 segment_list->weight = weight;
944 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
945 update_lb (sr_policy);
947 else /* Incorrect op. */
954 * @brief CLI for 'sr policies' command family
956 static clib_error_t *
957 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
958 vlib_cli_command_t * cmd)
960 ip6_sr_main_t *sm = &sr_main;
962 char is_del = 0, is_add = 0, is_mod = 0;
964 ip6_address_t bsid, next_address;
965 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
966 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
967 ip6_address_t *segments = 0, *this_seg;
970 u8 type = SR_POLICY_TYPE_DEFAULT;
972 void *ls_plugin_mem = 0;
974 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
976 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
978 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
980 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
983 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
985 else if (!is_add && !policy_set
986 && unformat (input, "index %d", &sr_policy_index))
988 else if (unformat (input, "weight %d", &weight));
990 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
992 vec_add2 (segments, this_seg, 1);
993 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
996 else if (unformat (input, "add sl"))
998 else if (unformat (input, "del sl index %d", &sl_index))
1000 else if (unformat (input, "mod sl index %d", &sl_index))
1002 else if (fib_table == (u32) ~ 0
1003 && unformat (input, "fib-table %d", &fib_table));
1004 else if (unformat (input, "encap"))
1006 else if (unformat (input, "insert"))
1008 else if (unformat (input, "spray"))
1009 type = SR_POLICY_TYPE_SPRAY;
1010 else if (unformat (input, "tef"))
1011 type = SR_POLICY_TYPE_TEF;
1012 else if (!behavior && unformat (input, "behavior"))
1014 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
1015 sr_policy_fn_registration_t **plugin_it = 0;
1018 pool_foreach (plugin, sm->policy_plugin_functions)
1020 vec_add1 (vec_plugins, plugin);
1024 vec_foreach (plugin_it, vec_plugins)
1027 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
1029 behavior = (*plugin_it)->sr_policy_function_number;
1036 return clib_error_return (0, "Invalid behavior");
1043 if (!is_add && !is_mod && !is_del)
1044 return clib_error_return (0, "Incorrect CLI");
1047 return clib_error_return (0, "No SR policy BSID or index specified");
1051 if (behavior && vec_len (segments) == 0)
1053 vec_add2 (segments, this_seg, 1);
1054 clib_memset (this_seg, 0, sizeof (*this_seg));
1057 if (vec_len (segments) == 0)
1058 return clib_error_return (0, "No Segment List specified");
1060 rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap,
1061 behavior, ls_plugin_mem);
1063 vec_free (segments);
1066 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1071 return clib_error_return (0, "No SL modification specified");
1072 if (operation != 1 && sl_index == (u32) ~ 0)
1073 return clib_error_return (0, "No Segment List index specified");
1074 if (operation == 1 && vec_len (segments) == 0)
1075 return clib_error_return (0, "No Segment List specified");
1076 if (operation == 3 && weight == (u32) ~ 0)
1077 return clib_error_return (0, "No new weight for the SL specified");
1079 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1080 sr_policy_index, fib_table, operation, segments,
1084 vec_free (segments);
1094 return clib_error_return (0,
1095 "There is already a FIB entry for the BindingSID address.\n"
1096 "The SR policy could not be created.");
1098 return clib_error_return (0, "The specified FIB table does not exist.");
1100 return clib_error_return (0,
1101 "The selected SR policy only contains ONE segment list. "
1102 "Please remove the SR policy instead");
1104 return clib_error_return (0,
1105 "Could not delete the segment list. "
1106 "It is not associated with that SR policy.");
1108 return clib_error_return (0,
1109 "Could not modify the segment list. "
1110 "The given SL is not associated with such SR policy.");
1112 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1118 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1119 .path = "sr policy",
1120 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1121 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1123 "Manipulation of SR policies.\n"
1124 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1125 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1126 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1127 "Each SR policy will be associated with a unique BindingSID.\n"
1128 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1129 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1130 "The add command will create a SR policy with its first segment list (sl)\n"
1131 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1132 "within an SR policy.\n"
1133 "The del command allows you to delete a SR policy along with all its associated\n"
1135 .function = sr_policy_command_fn,
1140 * @brief CLI to display onscreen all the SR policies
1142 static clib_error_t *
1143 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1144 vlib_cli_command_t * cmd)
1146 ip6_sr_main_t *sm = &sr_main;
1148 ip6_sr_sl_t *segment_list = 0;
1149 ip6_sr_policy_t *sr_policy = 0;
1150 ip6_sr_policy_t **vec_policies = 0;
1151 ip6_address_t *addr;
1155 vlib_cli_output (vm, "SR policies:");
1158 pool_foreach (sr_policy, sm->sr_policies)
1159 {vec_add1 (vec_policies, sr_policy); }
1162 vec_foreach_index (i, vec_policies)
1164 sr_policy = vec_policies[i];
1165 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1166 (u32) (sr_policy - sm->sr_policies),
1167 format_ip6_address, &sr_policy->bsid);
1168 vlib_cli_output (vm, "\tBehavior: %s",
1169 (sr_policy->is_encap ? "Encapsulation" :
1171 switch (sr_policy->type)
1173 case SR_POLICY_TYPE_SPRAY:
1174 vlib_cli_output (vm, "\tType: %s", "Spray");
1176 case SR_POLICY_TYPE_TEF:
1177 vlib_cli_output (vm, "\tType: %s",
1178 "TEF (Timestamp, Encapsulate, and Forward)");
1181 vlib_cli_output (vm, "\tType: %s", "Default");
1184 vlib_cli_output (vm, "\tFIB table: %u",
1185 (sr_policy->fib_table !=
1186 (u32) ~ 0 ? sr_policy->fib_table : 0));
1187 vlib_cli_output (vm, "\tSegment Lists:");
1188 vec_foreach (sl_index, sr_policy->segments_lists)
1191 s = format (s, "\t[%u].- ", *sl_index);
1192 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1193 s = format (s, "< ");
1194 vec_foreach (addr, segment_list->segments)
1196 s = format (s, "%U, ", format_ip6_address, addr);
1198 s = format (s, "\b\b > ");
1199 s = format (s, "weight: %u", segment_list->weight);
1200 vlib_cli_output (vm, " %v", s);
1202 vlib_cli_output (vm, "-----------");
1208 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1209 .path = "show sr policies",
1210 .short_help = "show sr policies",
1211 .function = show_sr_policies_command_fn,
1216 * @brief CLI to display onscreen the SR encaps source addr
1218 static clib_error_t *
1219 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1220 vlib_cli_command_t * cmd)
1222 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1223 sr_get_encaps_source ());
1229 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1230 .path = "show sr encaps source addr",
1231 .short_help = "show sr encaps source addr",
1232 .function = show_sr_encaps_source_command_fn,
1237 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1239 static clib_error_t *
1240 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1241 unformat_input_t * input,
1242 vlib_cli_command_t * cmd)
1244 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1250 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1251 .path = "show sr encaps hop-limit",
1252 .short_help = "show sr encaps hop-limit",
1253 .function = show_sr_encaps_hop_limit_command_fn,
1257 /*************************** SR rewrite graph node ****************************/
1259 * @brief Trace for the SR Policy Rewrite graph node
1262 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1265 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1266 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1267 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1270 (s, "SR-policy-rewrite: src %U dst %U",
1271 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1276 * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
1278 static_always_inline void
1279 srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1282 ip6_sr_header_t *srh;
1283 ip6_sr_pt_tlv_t *srh_pt_tlv;
1285 srh = (ip6_sr_header_t *) (ip0 + 1);
1288 (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
1289 sizeof (ip6_sr_header_t) +
1290 sizeof (ip6_address_t) * (srh->last_entry + 1));
1292 unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
1293 srh_pt_tlv->t64.sec = htobe32 (ts.sec);
1294 srh_pt_tlv->t64.nsec = htobe32 (ts.nsec);
1298 * @brief IPv6 encapsulation processing as per RFC2473
1300 static_always_inline void
1301 encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1302 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1308 ip0_encap->hop_limit -= 1;
1310 ip0->payload_length + sizeof (ip6_header_t) +
1311 clib_net_to_host_u16 (ip0_encap->payload_length);
1312 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1314 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1315 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1317 (clib_net_to_host_u32 (
1318 ip0_encap->ip_version_traffic_class_and_flow_label) &
1320 (flow_label & 0x0000ffff));
1321 if (policy_type == SR_POLICY_TYPE_TEF)
1322 srv6_tef_behavior (node, b0, ip0);
1326 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1329 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1330 vlib_frame_t * from_frame)
1332 ip6_sr_main_t *sm = &sr_main;
1333 u32 n_left_from, next_index, *from, *to_next;
1335 from = vlib_frame_vector_args (from_frame);
1336 n_left_from = from_frame->n_vectors;
1338 next_index = node->cached_next_index;
1340 int encap_pkts = 0, bsid_pkts = 0;
1342 while (n_left_from > 0)
1346 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1349 while (n_left_from >= 8 && n_left_to_next >= 4)
1351 u32 bi0, bi1, bi2, bi3;
1352 vlib_buffer_t *b0, *b1, *b2, *b3;
1353 u32 next0, next1, next2, next3;
1354 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1355 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1356 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1357 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1359 /* Prefetch next iteration. */
1361 vlib_buffer_t *p4, *p5, *p6, *p7;
1363 p4 = vlib_get_buffer (vm, from[4]);
1364 p5 = vlib_get_buffer (vm, from[5]);
1365 p6 = vlib_get_buffer (vm, from[6]);
1366 p7 = vlib_get_buffer (vm, from[7]);
1368 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1369 vlib_prefetch_buffer_header (p4, LOAD);
1370 vlib_prefetch_buffer_header (p5, LOAD);
1371 vlib_prefetch_buffer_header (p6, LOAD);
1372 vlib_prefetch_buffer_header (p7, LOAD);
1374 clib_prefetch_store (p4->data);
1375 clib_prefetch_store (p5->data);
1376 clib_prefetch_store (p6->data);
1377 clib_prefetch_store (p7->data);
1380 to_next[0] = bi0 = from[0];
1381 to_next[1] = bi1 = from[1];
1382 to_next[2] = bi2 = from[2];
1383 to_next[3] = bi3 = from[3];
1387 n_left_to_next -= 4;
1389 b0 = vlib_get_buffer (vm, bi0);
1390 b1 = vlib_get_buffer (vm, bi1);
1391 b2 = vlib_get_buffer (vm, bi2);
1392 b3 = vlib_get_buffer (vm, bi3);
1395 pool_elt_at_index (sm->sid_lists,
1396 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1398 pool_elt_at_index (sm->sid_lists,
1399 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1401 pool_elt_at_index (sm->sid_lists,
1402 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1404 pool_elt_at_index (sm->sid_lists,
1405 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1407 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1408 vec_len (sl0->rewrite));
1409 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1410 vec_len (sl1->rewrite));
1411 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1412 vec_len (sl2->rewrite));
1413 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1414 vec_len (sl3->rewrite));
1416 ip0_encap = vlib_buffer_get_current (b0);
1417 ip1_encap = vlib_buffer_get_current (b1);
1418 ip2_encap = vlib_buffer_get_current (b2);
1419 ip3_encap = vlib_buffer_get_current (b3);
1421 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1422 sl0->rewrite, vec_len (sl0->rewrite));
1423 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1424 sl1->rewrite, vec_len (sl1->rewrite));
1425 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1426 sl2->rewrite, vec_len (sl2->rewrite));
1427 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1428 sl3->rewrite, vec_len (sl3->rewrite));
1430 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1431 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1432 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1433 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1435 ip0 = vlib_buffer_get_current (b0);
1436 ip1 = vlib_buffer_get_current (b1);
1437 ip2 = vlib_buffer_get_current (b2);
1438 ip3 = vlib_buffer_get_current (b3);
1440 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1441 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1442 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1443 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
1445 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1446 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1447 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1448 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1450 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1452 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1454 sr_policy_rewrite_trace_t *tr =
1455 vlib_add_trace (vm, node, b0, sizeof (*tr));
1456 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1457 sizeof (tr->src.as_u8));
1458 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1459 sizeof (tr->dst.as_u8));
1462 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1464 sr_policy_rewrite_trace_t *tr =
1465 vlib_add_trace (vm, node, b1, sizeof (*tr));
1466 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1467 sizeof (tr->src.as_u8));
1468 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1469 sizeof (tr->dst.as_u8));
1472 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1474 sr_policy_rewrite_trace_t *tr =
1475 vlib_add_trace (vm, node, b2, sizeof (*tr));
1476 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1477 sizeof (tr->src.as_u8));
1478 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1479 sizeof (tr->dst.as_u8));
1482 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1484 sr_policy_rewrite_trace_t *tr =
1485 vlib_add_trace (vm, node, b3, sizeof (*tr));
1486 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1487 sizeof (tr->src.as_u8));
1488 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1489 sizeof (tr->dst.as_u8));
1494 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1495 n_left_to_next, bi0, bi1, bi2, bi3,
1496 next0, next1, next2, next3);
1499 /* Single loop for potentially the last three packets */
1500 while (n_left_from > 0 && n_left_to_next > 0)
1504 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1506 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1513 n_left_to_next -= 1;
1514 b0 = vlib_get_buffer (vm, bi0);
1517 pool_elt_at_index (sm->sid_lists,
1518 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1519 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1520 vec_len (sl0->rewrite));
1522 ip0_encap = vlib_buffer_get_current (b0);
1524 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1525 sl0->rewrite, vec_len (sl0->rewrite));
1526 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1528 ip0 = vlib_buffer_get_current (b0);
1530 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1532 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1534 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1535 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1537 sr_policy_rewrite_trace_t *tr =
1538 vlib_add_trace (vm, node, b0, sizeof (*tr));
1539 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1540 sizeof (tr->src.as_u8));
1541 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1542 sizeof (tr->dst.as_u8));
1546 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1547 n_left_to_next, bi0, next0);
1550 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1553 /* Update counters */
1554 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1555 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1557 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1558 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1561 return from_frame->n_vectors;
1565 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1566 .function = sr_policy_rewrite_encaps,
1567 .name = "sr-pl-rewrite-encaps",
1568 .vector_size = sizeof (u32),
1569 .format_trace = format_sr_policy_rewrite_trace,
1570 .type = VLIB_NODE_TYPE_INTERNAL,
1571 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1572 .error_strings = sr_policy_rewrite_error_strings,
1573 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1575 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1576 foreach_sr_policy_rewrite_next
1583 * @brief IPv4 encapsulation processing as per RFC2473
1585 static_always_inline void
1586 encaps_processing_v4 (vlib_node_runtime_t * node,
1588 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1591 ip6_sr_header_t *sr0;
1596 /* Inner IPv4: Decrement TTL & update checksum */
1597 ip0_encap->ttl -= 1;
1598 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1599 checksum0 += checksum0 >= 0xffff;
1600 ip0_encap->checksum = checksum0;
1602 /* Outer IPv6: Update length, FL, proto */
1603 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1604 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1605 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1606 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1607 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1608 (flow_label & 0x0000ffff));
1609 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1611 sr0 = (void *) (ip0 + 1);
1612 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1615 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1619 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1622 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1623 vlib_frame_t * from_frame)
1625 ip6_sr_main_t *sm = &sr_main;
1626 u32 n_left_from, next_index, *from, *to_next;
1628 from = vlib_frame_vector_args (from_frame);
1629 n_left_from = from_frame->n_vectors;
1631 next_index = node->cached_next_index;
1633 int encap_pkts = 0, bsid_pkts = 0;
1635 while (n_left_from > 0)
1639 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1642 while (n_left_from >= 8 && n_left_to_next >= 4)
1644 u32 bi0, bi1, bi2, bi3;
1645 vlib_buffer_t *b0, *b1, *b2, *b3;
1646 u32 next0, next1, next2, next3;
1647 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1648 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1649 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1650 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1652 /* Prefetch next iteration. */
1654 vlib_buffer_t *p4, *p5, *p6, *p7;
1656 p4 = vlib_get_buffer (vm, from[4]);
1657 p5 = vlib_get_buffer (vm, from[5]);
1658 p6 = vlib_get_buffer (vm, from[6]);
1659 p7 = vlib_get_buffer (vm, from[7]);
1661 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1662 vlib_prefetch_buffer_header (p4, LOAD);
1663 vlib_prefetch_buffer_header (p5, LOAD);
1664 vlib_prefetch_buffer_header (p6, LOAD);
1665 vlib_prefetch_buffer_header (p7, LOAD);
1667 clib_prefetch_store (p4->data);
1668 clib_prefetch_store (p5->data);
1669 clib_prefetch_store (p6->data);
1670 clib_prefetch_store (p7->data);
1673 to_next[0] = bi0 = from[0];
1674 to_next[1] = bi1 = from[1];
1675 to_next[2] = bi2 = from[2];
1676 to_next[3] = bi3 = from[3];
1680 n_left_to_next -= 4;
1682 b0 = vlib_get_buffer (vm, bi0);
1683 b1 = vlib_get_buffer (vm, bi1);
1684 b2 = vlib_get_buffer (vm, bi2);
1685 b3 = vlib_get_buffer (vm, bi3);
1688 pool_elt_at_index (sm->sid_lists,
1689 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1691 pool_elt_at_index (sm->sid_lists,
1692 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1694 pool_elt_at_index (sm->sid_lists,
1695 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1697 pool_elt_at_index (sm->sid_lists,
1698 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1699 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1700 vec_len (sl0->rewrite));
1701 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1702 vec_len (sl1->rewrite));
1703 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1704 vec_len (sl2->rewrite));
1705 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1706 vec_len (sl3->rewrite));
1708 ip0_encap = vlib_buffer_get_current (b0);
1709 ip1_encap = vlib_buffer_get_current (b1);
1710 ip2_encap = vlib_buffer_get_current (b2);
1711 ip3_encap = vlib_buffer_get_current (b3);
1713 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1714 sl0->rewrite, vec_len (sl0->rewrite));
1715 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1716 sl1->rewrite, vec_len (sl1->rewrite));
1717 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1718 sl2->rewrite, vec_len (sl2->rewrite));
1719 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1720 sl3->rewrite, vec_len (sl3->rewrite));
1722 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1723 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1724 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1725 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1727 ip0 = vlib_buffer_get_current (b0);
1728 ip1 = vlib_buffer_get_current (b1);
1729 ip2 = vlib_buffer_get_current (b2);
1730 ip3 = vlib_buffer_get_current (b3);
1732 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1733 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1734 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1735 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1737 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1738 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1739 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1740 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1742 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1744 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1746 sr_policy_rewrite_trace_t *tr =
1747 vlib_add_trace (vm, node, b0, sizeof (*tr));
1748 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1749 sizeof (tr->src.as_u8));
1750 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1751 sizeof (tr->dst.as_u8));
1754 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1756 sr_policy_rewrite_trace_t *tr =
1757 vlib_add_trace (vm, node, b1, sizeof (*tr));
1758 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1759 sizeof (tr->src.as_u8));
1760 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1761 sizeof (tr->dst.as_u8));
1764 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1766 sr_policy_rewrite_trace_t *tr =
1767 vlib_add_trace (vm, node, b2, sizeof (*tr));
1768 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1769 sizeof (tr->src.as_u8));
1770 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1771 sizeof (tr->dst.as_u8));
1774 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1776 sr_policy_rewrite_trace_t *tr =
1777 vlib_add_trace (vm, node, b3, sizeof (*tr));
1778 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1779 sizeof (tr->src.as_u8));
1780 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1781 sizeof (tr->dst.as_u8));
1786 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1787 n_left_to_next, bi0, bi1, bi2, bi3,
1788 next0, next1, next2, next3);
1791 /* Single loop for potentially the last three packets */
1792 while (n_left_from > 0 && n_left_to_next > 0)
1796 ip6_header_t *ip0 = 0;
1797 ip4_header_t *ip0_encap = 0;
1799 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1806 n_left_to_next -= 1;
1807 b0 = vlib_get_buffer (vm, bi0);
1810 pool_elt_at_index (sm->sid_lists,
1811 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1812 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1813 vec_len (sl0->rewrite));
1815 ip0_encap = vlib_buffer_get_current (b0);
1817 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1818 sl0->rewrite, vec_len (sl0->rewrite));
1819 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1821 ip0 = vlib_buffer_get_current (b0);
1823 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1825 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1827 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1828 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1830 sr_policy_rewrite_trace_t *tr =
1831 vlib_add_trace (vm, node, b0, sizeof (*tr));
1832 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1833 sizeof (tr->src.as_u8));
1834 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1835 sizeof (tr->dst.as_u8));
1839 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1840 n_left_to_next, bi0, next0);
1843 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1846 /* Update counters */
1847 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1848 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1850 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1851 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1854 return from_frame->n_vectors;
1858 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1859 .function = sr_policy_rewrite_encaps_v4,
1860 .name = "sr-pl-rewrite-encaps-v4",
1861 .vector_size = sizeof (u32),
1862 .format_trace = format_sr_policy_rewrite_trace,
1863 .type = VLIB_NODE_TYPE_INTERNAL,
1864 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1865 .error_strings = sr_policy_rewrite_error_strings,
1866 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1868 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1869 foreach_sr_policy_rewrite_next
1876 ip_flow_hash (void *data)
1878 ip4_header_t *iph = (ip4_header_t *) data;
1880 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1881 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1883 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1889 return (*((u64 *) m) & 0xffffffffffff);
1893 l2_flow_hash (vlib_buffer_t * b0)
1895 ethernet_header_t *eh;
1897 uword is_ip, eh_size;
1900 eh = vlib_buffer_get_current (b0);
1901 eh_type = clib_net_to_host_u16 (eh->type);
1902 eh_size = ethernet_buffer_header_size (b0);
1904 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1906 /* since we have 2 cache lines, use them */
1908 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1912 b = mac_to_u64 ((u8 *) eh->dst_address);
1913 c = mac_to_u64 ((u8 *) eh->src_address);
1914 hash_mix64 (a, b, c);
1920 * @brief Graph node for applying a SR policy into a L2 frame
1923 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1924 vlib_frame_t * from_frame)
1926 ip6_sr_main_t *sm = &sr_main;
1927 u32 n_left_from, next_index, *from, *to_next;
1929 from = vlib_frame_vector_args (from_frame);
1930 n_left_from = from_frame->n_vectors;
1932 next_index = node->cached_next_index;
1934 int encap_pkts = 0, bsid_pkts = 0;
1936 while (n_left_from > 0)
1940 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1943 while (n_left_from >= 8 && n_left_to_next >= 4)
1945 u32 bi0, bi1, bi2, bi3;
1946 vlib_buffer_t *b0, *b1, *b2, *b3;
1947 u32 next0, next1, next2, next3;
1948 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1949 ethernet_header_t *en0, *en1, *en2, *en3;
1950 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1951 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1952 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1953 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1954 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1956 /* Prefetch next iteration. */
1958 vlib_buffer_t *p4, *p5, *p6, *p7;
1960 p4 = vlib_get_buffer (vm, from[4]);
1961 p5 = vlib_get_buffer (vm, from[5]);
1962 p6 = vlib_get_buffer (vm, from[6]);
1963 p7 = vlib_get_buffer (vm, from[7]);
1965 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1966 vlib_prefetch_buffer_header (p4, LOAD);
1967 vlib_prefetch_buffer_header (p5, LOAD);
1968 vlib_prefetch_buffer_header (p6, LOAD);
1969 vlib_prefetch_buffer_header (p7, LOAD);
1971 clib_prefetch_store (p4->data);
1972 clib_prefetch_store (p5->data);
1973 clib_prefetch_store (p6->data);
1974 clib_prefetch_store (p7->data);
1977 to_next[0] = bi0 = from[0];
1978 to_next[1] = bi1 = from[1];
1979 to_next[2] = bi2 = from[2];
1980 to_next[3] = bi3 = from[3];
1984 n_left_to_next -= 4;
1986 b0 = vlib_get_buffer (vm, bi0);
1987 b1 = vlib_get_buffer (vm, bi1);
1988 b2 = vlib_get_buffer (vm, bi2);
1989 b3 = vlib_get_buffer (vm, bi3);
1991 sp0 = pool_elt_at_index (sm->sr_policies,
1992 sm->sw_iface_sr_policies[vnet_buffer
1996 sp1 = pool_elt_at_index (sm->sr_policies,
1997 sm->sw_iface_sr_policies[vnet_buffer
2001 sp2 = pool_elt_at_index (sm->sr_policies,
2002 sm->sw_iface_sr_policies[vnet_buffer
2006 sp3 = pool_elt_at_index (sm->sr_policies,
2007 sm->sw_iface_sr_policies[vnet_buffer
2010 flow_label0 = l2_flow_hash (b0);
2011 flow_label1 = l2_flow_hash (b1);
2012 flow_label2 = l2_flow_hash (b2);
2013 flow_label3 = l2_flow_hash (b3);
2015 if (vec_len (sp0->segments_lists) == 1)
2016 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2019 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2020 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2021 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2022 (vec_len (sp0->segments_lists) - 1))];
2025 if (vec_len (sp1->segments_lists) == 1)
2026 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
2029 vnet_buffer (b1)->ip.flow_hash = flow_label1;
2030 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
2031 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
2032 (vec_len (sp1->segments_lists) - 1))];
2035 if (vec_len (sp2->segments_lists) == 1)
2036 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
2039 vnet_buffer (b2)->ip.flow_hash = flow_label2;
2040 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
2041 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
2042 (vec_len (sp2->segments_lists) - 1))];
2045 if (vec_len (sp3->segments_lists) == 1)
2046 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
2049 vnet_buffer (b3)->ip.flow_hash = flow_label3;
2050 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
2051 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
2052 (vec_len (sp3->segments_lists) - 1))];
2056 pool_elt_at_index (sm->sid_lists,
2057 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2059 pool_elt_at_index (sm->sid_lists,
2060 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2062 pool_elt_at_index (sm->sid_lists,
2063 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2065 pool_elt_at_index (sm->sid_lists,
2066 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2068 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2069 vec_len (sl0->rewrite));
2070 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2071 vec_len (sl1->rewrite));
2072 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2073 vec_len (sl2->rewrite));
2074 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2075 vec_len (sl3->rewrite));
2077 en0 = vlib_buffer_get_current (b0);
2078 en1 = vlib_buffer_get_current (b1);
2079 en2 = vlib_buffer_get_current (b2);
2080 en3 = vlib_buffer_get_current (b3);
2082 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2083 sl0->rewrite, vec_len (sl0->rewrite));
2084 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2085 sl1->rewrite, vec_len (sl1->rewrite));
2086 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2087 sl2->rewrite, vec_len (sl2->rewrite));
2088 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2089 sl3->rewrite, vec_len (sl3->rewrite));
2091 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2092 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2093 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2094 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2096 ip0 = vlib_buffer_get_current (b0);
2097 ip1 = vlib_buffer_get_current (b1);
2098 ip2 = vlib_buffer_get_current (b2);
2099 ip3 = vlib_buffer_get_current (b3);
2101 ip0->payload_length =
2102 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2103 ip1->payload_length =
2104 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2105 ip2->payload_length =
2106 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2107 ip3->payload_length =
2108 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2110 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2112 sr0 = (void *) (ip0 + 1);
2113 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2116 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2118 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2120 sr1 = (void *) (ip1 + 1);
2121 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2124 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2126 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2128 sr2 = (void *) (ip2 + 1);
2129 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2132 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2134 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2136 sr3 = (void *) (ip3 + 1);
2137 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2140 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2142 /* TC is set to 0 for all ethernet frames, should be taken from COS
2143 * od DSCP of encapsulated packet in the future */
2144 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2145 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2146 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2147 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2148 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2149 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2150 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2151 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2153 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2155 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2157 sr_policy_rewrite_trace_t *tr =
2158 vlib_add_trace (vm, node, b0, sizeof (*tr));
2159 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2160 sizeof (tr->src.as_u8));
2161 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2162 sizeof (tr->dst.as_u8));
2165 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2167 sr_policy_rewrite_trace_t *tr =
2168 vlib_add_trace (vm, node, b1, sizeof (*tr));
2169 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2170 sizeof (tr->src.as_u8));
2171 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2172 sizeof (tr->dst.as_u8));
2175 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2177 sr_policy_rewrite_trace_t *tr =
2178 vlib_add_trace (vm, node, b2, sizeof (*tr));
2179 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2180 sizeof (tr->src.as_u8));
2181 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2182 sizeof (tr->dst.as_u8));
2185 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2187 sr_policy_rewrite_trace_t *tr =
2188 vlib_add_trace (vm, node, b3, sizeof (*tr));
2189 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2190 sizeof (tr->src.as_u8));
2191 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2192 sizeof (tr->dst.as_u8));
2197 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2198 n_left_to_next, bi0, bi1, bi2, bi3,
2199 next0, next1, next2, next3);
2202 /* Single loop for potentially the last three packets */
2203 while (n_left_from > 0 && n_left_to_next > 0)
2207 ip6_header_t *ip0 = 0;
2208 ip6_sr_header_t *sr0;
2209 ethernet_header_t *en0;
2210 ip6_sr_policy_t *sp0;
2212 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2220 n_left_to_next -= 1;
2221 b0 = vlib_get_buffer (vm, bi0);
2223 /* Find the SR policy */
2224 sp0 = pool_elt_at_index (sm->sr_policies,
2225 sm->sw_iface_sr_policies[vnet_buffer
2228 flow_label0 = l2_flow_hash (b0);
2230 /* In case there is more than one SL, LB among them */
2231 if (vec_len (sp0->segments_lists) == 1)
2232 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2235 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2236 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2237 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2238 (vec_len (sp0->segments_lists) - 1))];
2241 pool_elt_at_index (sm->sid_lists,
2242 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2244 vec_len (sl0->rewrite));
2246 en0 = vlib_buffer_get_current (b0);
2248 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2249 sl0->rewrite, vec_len (sl0->rewrite));
2251 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2253 ip0 = vlib_buffer_get_current (b0);
2255 ip0->payload_length =
2256 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2258 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2260 sr0 = (void *) (ip0 + 1);
2261 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2264 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2266 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2267 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2269 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2270 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2272 sr_policy_rewrite_trace_t *tr =
2273 vlib_add_trace (vm, node, b0, sizeof (*tr));
2274 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2275 sizeof (tr->src.as_u8));
2276 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2277 sizeof (tr->dst.as_u8));
2281 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2282 n_left_to_next, bi0, next0);
2285 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2288 /* Update counters */
2289 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2290 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2292 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2293 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2296 return from_frame->n_vectors;
2300 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2301 .function = sr_policy_rewrite_encaps_l2,
2302 .name = "sr-pl-rewrite-encaps-l2",
2303 .vector_size = sizeof (u32),
2304 .format_trace = format_sr_policy_rewrite_trace,
2305 .type = VLIB_NODE_TYPE_INTERNAL,
2306 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2307 .error_strings = sr_policy_rewrite_error_strings,
2308 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2310 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2311 foreach_sr_policy_rewrite_next
2318 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2321 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2322 vlib_frame_t * from_frame)
2324 ip6_sr_main_t *sm = &sr_main;
2325 u32 n_left_from, next_index, *from, *to_next;
2327 from = vlib_frame_vector_args (from_frame);
2328 n_left_from = from_frame->n_vectors;
2330 next_index = node->cached_next_index;
2332 int insert_pkts = 0, bsid_pkts = 0;
2334 while (n_left_from > 0)
2338 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2341 while (n_left_from >= 8 && n_left_to_next >= 4)
2343 u32 bi0, bi1, bi2, bi3;
2344 vlib_buffer_t *b0, *b1, *b2, *b3;
2345 u32 next0, next1, next2, next3;
2346 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2347 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2348 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2349 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2350 u16 new_l0, new_l1, new_l2, new_l3;
2352 /* Prefetch next iteration. */
2354 vlib_buffer_t *p4, *p5, *p6, *p7;
2356 p4 = vlib_get_buffer (vm, from[4]);
2357 p5 = vlib_get_buffer (vm, from[5]);
2358 p6 = vlib_get_buffer (vm, from[6]);
2359 p7 = vlib_get_buffer (vm, from[7]);
2361 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2362 vlib_prefetch_buffer_header (p4, LOAD);
2363 vlib_prefetch_buffer_header (p5, LOAD);
2364 vlib_prefetch_buffer_header (p6, LOAD);
2365 vlib_prefetch_buffer_header (p7, LOAD);
2367 clib_prefetch_store (p4->data);
2368 clib_prefetch_store (p5->data);
2369 clib_prefetch_store (p6->data);
2370 clib_prefetch_store (p7->data);
2373 to_next[0] = bi0 = from[0];
2374 to_next[1] = bi1 = from[1];
2375 to_next[2] = bi2 = from[2];
2376 to_next[3] = bi3 = from[3];
2380 n_left_to_next -= 4;
2382 b0 = vlib_get_buffer (vm, bi0);
2383 b1 = vlib_get_buffer (vm, bi1);
2384 b2 = vlib_get_buffer (vm, bi2);
2385 b3 = vlib_get_buffer (vm, bi3);
2388 pool_elt_at_index (sm->sid_lists,
2389 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2391 pool_elt_at_index (sm->sid_lists,
2392 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2394 pool_elt_at_index (sm->sid_lists,
2395 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2397 pool_elt_at_index (sm->sid_lists,
2398 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2399 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2400 vec_len (sl0->rewrite));
2401 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2402 vec_len (sl1->rewrite));
2403 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2404 vec_len (sl2->rewrite));
2405 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2406 vec_len (sl3->rewrite));
2408 ip0 = vlib_buffer_get_current (b0);
2409 ip1 = vlib_buffer_get_current (b1);
2410 ip2 = vlib_buffer_get_current (b2);
2411 ip3 = vlib_buffer_get_current (b3);
2413 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2415 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2416 ip6_ext_header_len (ip0 + 1));
2418 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2420 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2422 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2423 ip6_ext_header_len (ip1 + 1));
2425 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2427 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2429 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2430 ip6_ext_header_len (ip2 + 1));
2432 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2434 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2436 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2437 ip6_ext_header_len (ip3 + 1));
2439 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2441 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2442 (void *) sr0 - (void *) ip0);
2443 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2444 (void *) sr1 - (void *) ip1);
2445 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2446 (void *) sr2 - (void *) ip2);
2447 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2448 (void *) sr3 - (void *) ip3);
2450 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2451 sl0->rewrite, vec_len (sl0->rewrite));
2452 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2453 sl1->rewrite, vec_len (sl1->rewrite));
2454 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2455 sl2->rewrite, vec_len (sl2->rewrite));
2456 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2457 sl3->rewrite, vec_len (sl3->rewrite));
2459 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2460 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2461 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2462 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2464 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2465 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2466 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2467 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2469 ip0->hop_limit -= 1;
2470 ip1->hop_limit -= 1;
2471 ip2->hop_limit -= 1;
2472 ip3->hop_limit -= 1;
2475 clib_net_to_host_u16 (ip0->payload_length) +
2476 vec_len (sl0->rewrite);
2478 clib_net_to_host_u16 (ip1->payload_length) +
2479 vec_len (sl1->rewrite);
2481 clib_net_to_host_u16 (ip2->payload_length) +
2482 vec_len (sl2->rewrite);
2484 clib_net_to_host_u16 (ip3->payload_length) +
2485 vec_len (sl3->rewrite);
2487 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2488 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2489 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2490 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2492 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2493 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2494 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2495 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2497 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2498 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2499 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2500 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2501 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2502 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2503 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2504 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2506 ip0->dst_address.as_u64[0] =
2507 (sr0->segments + sr0->segments_left)->as_u64[0];
2508 ip0->dst_address.as_u64[1] =
2509 (sr0->segments + sr0->segments_left)->as_u64[1];
2510 ip1->dst_address.as_u64[0] =
2511 (sr1->segments + sr1->segments_left)->as_u64[0];
2512 ip1->dst_address.as_u64[1] =
2513 (sr1->segments + sr1->segments_left)->as_u64[1];
2514 ip2->dst_address.as_u64[0] =
2515 (sr2->segments + sr2->segments_left)->as_u64[0];
2516 ip2->dst_address.as_u64[1] =
2517 (sr2->segments + sr2->segments_left)->as_u64[1];
2518 ip3->dst_address.as_u64[0] =
2519 (sr3->segments + sr3->segments_left)->as_u64[0];
2520 ip3->dst_address.as_u64[1] =
2521 (sr3->segments + sr3->segments_left)->as_u64[1];
2523 ip6_ext_header_t *ip_ext;
2524 if (ip0 + 1 == (void *) sr0)
2526 sr0->protocol = ip0->protocol;
2527 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2531 ip_ext = (void *) (ip0 + 1);
2532 sr0->protocol = ip_ext->next_hdr;
2533 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2536 if (ip1 + 1 == (void *) sr1)
2538 sr1->protocol = ip1->protocol;
2539 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2543 ip_ext = (void *) (ip2 + 1);
2544 sr2->protocol = ip_ext->next_hdr;
2545 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2548 if (ip2 + 1 == (void *) sr2)
2550 sr2->protocol = ip2->protocol;
2551 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2555 ip_ext = (void *) (ip2 + 1);
2556 sr2->protocol = ip_ext->next_hdr;
2557 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2560 if (ip3 + 1 == (void *) sr3)
2562 sr3->protocol = ip3->protocol;
2563 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2567 ip_ext = (void *) (ip3 + 1);
2568 sr3->protocol = ip_ext->next_hdr;
2569 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2574 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2576 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2578 sr_policy_rewrite_trace_t *tr =
2579 vlib_add_trace (vm, node, b0, sizeof (*tr));
2580 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2581 sizeof (tr->src.as_u8));
2582 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2583 sizeof (tr->dst.as_u8));
2586 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2588 sr_policy_rewrite_trace_t *tr =
2589 vlib_add_trace (vm, node, b1, sizeof (*tr));
2590 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2591 sizeof (tr->src.as_u8));
2592 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2593 sizeof (tr->dst.as_u8));
2596 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2598 sr_policy_rewrite_trace_t *tr =
2599 vlib_add_trace (vm, node, b2, sizeof (*tr));
2600 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2601 sizeof (tr->src.as_u8));
2602 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2603 sizeof (tr->dst.as_u8));
2606 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2608 sr_policy_rewrite_trace_t *tr =
2609 vlib_add_trace (vm, node, b3, sizeof (*tr));
2610 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2611 sizeof (tr->src.as_u8));
2612 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2613 sizeof (tr->dst.as_u8));
2617 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2618 n_left_to_next, bi0, bi1, bi2, bi3,
2619 next0, next1, next2, next3);
2622 /* Single loop for potentially the last three packets */
2623 while (n_left_from > 0 && n_left_to_next > 0)
2627 ip6_header_t *ip0 = 0;
2628 ip6_sr_header_t *sr0 = 0;
2630 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2638 n_left_to_next -= 1;
2640 b0 = vlib_get_buffer (vm, bi0);
2642 pool_elt_at_index (sm->sid_lists,
2643 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2644 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2645 vec_len (sl0->rewrite));
2647 ip0 = vlib_buffer_get_current (b0);
2649 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2651 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2652 ip6_ext_header_len (ip0 + 1));
2654 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2656 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2657 (void *) sr0 - (void *) ip0);
2658 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2659 sl0->rewrite, vec_len (sl0->rewrite));
2661 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2663 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2664 ip0->hop_limit -= 1;
2666 clib_net_to_host_u16 (ip0->payload_length) +
2667 vec_len (sl0->rewrite);
2668 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2670 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2671 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2672 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2674 ip0->dst_address.as_u64[0] =
2675 (sr0->segments + sr0->segments_left)->as_u64[0];
2676 ip0->dst_address.as_u64[1] =
2677 (sr0->segments + sr0->segments_left)->as_u64[1];
2679 if (ip0 + 1 == (void *) sr0)
2681 sr0->protocol = ip0->protocol;
2682 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2686 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2687 sr0->protocol = ip_ext->next_hdr;
2688 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2691 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2692 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2694 sr_policy_rewrite_trace_t *tr =
2695 vlib_add_trace (vm, node, b0, sizeof (*tr));
2696 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2697 sizeof (tr->src.as_u8));
2698 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2699 sizeof (tr->dst.as_u8));
2704 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2705 n_left_to_next, bi0, next0);
2708 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2711 /* Update counters */
2712 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2713 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2715 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2716 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2718 return from_frame->n_vectors;
2722 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2723 .function = sr_policy_rewrite_insert,
2724 .name = "sr-pl-rewrite-insert",
2725 .vector_size = sizeof (u32),
2726 .format_trace = format_sr_policy_rewrite_trace,
2727 .type = VLIB_NODE_TYPE_INTERNAL,
2728 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2729 .error_strings = sr_policy_rewrite_error_strings,
2730 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2732 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2733 foreach_sr_policy_rewrite_next
2740 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2743 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2744 vlib_frame_t * from_frame)
2746 ip6_sr_main_t *sm = &sr_main;
2747 u32 n_left_from, next_index, *from, *to_next;
2749 from = vlib_frame_vector_args (from_frame);
2750 n_left_from = from_frame->n_vectors;
2752 next_index = node->cached_next_index;
2754 int insert_pkts = 0, bsid_pkts = 0;
2756 while (n_left_from > 0)
2760 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2763 while (n_left_from >= 8 && n_left_to_next >= 4)
2765 u32 bi0, bi1, bi2, bi3;
2766 vlib_buffer_t *b0, *b1, *b2, *b3;
2767 u32 next0, next1, next2, next3;
2768 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2769 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2770 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2771 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2772 u16 new_l0, new_l1, new_l2, new_l3;
2774 /* Prefetch next iteration. */
2776 vlib_buffer_t *p4, *p5, *p6, *p7;
2778 p4 = vlib_get_buffer (vm, from[4]);
2779 p5 = vlib_get_buffer (vm, from[5]);
2780 p6 = vlib_get_buffer (vm, from[6]);
2781 p7 = vlib_get_buffer (vm, from[7]);
2783 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2784 vlib_prefetch_buffer_header (p4, LOAD);
2785 vlib_prefetch_buffer_header (p5, LOAD);
2786 vlib_prefetch_buffer_header (p6, LOAD);
2787 vlib_prefetch_buffer_header (p7, LOAD);
2789 clib_prefetch_store (p4->data);
2790 clib_prefetch_store (p5->data);
2791 clib_prefetch_store (p6->data);
2792 clib_prefetch_store (p7->data);
2795 to_next[0] = bi0 = from[0];
2796 to_next[1] = bi1 = from[1];
2797 to_next[2] = bi2 = from[2];
2798 to_next[3] = bi3 = from[3];
2802 n_left_to_next -= 4;
2804 b0 = vlib_get_buffer (vm, bi0);
2805 b1 = vlib_get_buffer (vm, bi1);
2806 b2 = vlib_get_buffer (vm, bi2);
2807 b3 = vlib_get_buffer (vm, bi3);
2810 pool_elt_at_index (sm->sid_lists,
2811 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2813 pool_elt_at_index (sm->sid_lists,
2814 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2816 pool_elt_at_index (sm->sid_lists,
2817 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2819 pool_elt_at_index (sm->sid_lists,
2820 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2821 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2822 vec_len (sl0->rewrite_bsid));
2823 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2824 vec_len (sl1->rewrite_bsid));
2825 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2826 vec_len (sl2->rewrite_bsid));
2827 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2828 vec_len (sl3->rewrite_bsid));
2830 ip0 = vlib_buffer_get_current (b0);
2831 ip1 = vlib_buffer_get_current (b1);
2832 ip2 = vlib_buffer_get_current (b2);
2833 ip3 = vlib_buffer_get_current (b3);
2835 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2837 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2838 ip6_ext_header_len (ip0 + 1));
2840 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2842 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2844 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2845 ip6_ext_header_len (ip1 + 1));
2847 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2849 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2851 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2852 ip6_ext_header_len (ip2 + 1));
2854 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2856 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2858 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2859 ip6_ext_header_len (ip3 + 1));
2861 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2863 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2864 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2865 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2866 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2867 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2868 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2869 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2870 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2872 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2873 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2874 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2875 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2876 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2877 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2878 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2879 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2881 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2882 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2883 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2884 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2886 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2887 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2888 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2889 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2891 ip0->hop_limit -= 1;
2892 ip1->hop_limit -= 1;
2893 ip2->hop_limit -= 1;
2894 ip3->hop_limit -= 1;
2897 clib_net_to_host_u16 (ip0->payload_length) +
2898 vec_len (sl0->rewrite_bsid);
2900 clib_net_to_host_u16 (ip1->payload_length) +
2901 vec_len (sl1->rewrite_bsid);
2903 clib_net_to_host_u16 (ip2->payload_length) +
2904 vec_len (sl2->rewrite_bsid);
2906 clib_net_to_host_u16 (ip3->payload_length) +
2907 vec_len (sl3->rewrite_bsid);
2909 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2910 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2911 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2912 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2914 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2915 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2916 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2917 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2919 ip0->dst_address.as_u64[0] =
2920 (sr0->segments + sr0->segments_left)->as_u64[0];
2921 ip0->dst_address.as_u64[1] =
2922 (sr0->segments + sr0->segments_left)->as_u64[1];
2923 ip1->dst_address.as_u64[0] =
2924 (sr1->segments + sr1->segments_left)->as_u64[0];
2925 ip1->dst_address.as_u64[1] =
2926 (sr1->segments + sr1->segments_left)->as_u64[1];
2927 ip2->dst_address.as_u64[0] =
2928 (sr2->segments + sr2->segments_left)->as_u64[0];
2929 ip2->dst_address.as_u64[1] =
2930 (sr2->segments + sr2->segments_left)->as_u64[1];
2931 ip3->dst_address.as_u64[0] =
2932 (sr3->segments + sr3->segments_left)->as_u64[0];
2933 ip3->dst_address.as_u64[1] =
2934 (sr3->segments + sr3->segments_left)->as_u64[1];
2936 ip6_ext_header_t *ip_ext;
2937 if (ip0 + 1 == (void *) sr0)
2939 sr0->protocol = ip0->protocol;
2940 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2944 ip_ext = (void *) (ip0 + 1);
2945 sr0->protocol = ip_ext->next_hdr;
2946 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2949 if (ip1 + 1 == (void *) sr1)
2951 sr1->protocol = ip1->protocol;
2952 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2956 ip_ext = (void *) (ip2 + 1);
2957 sr2->protocol = ip_ext->next_hdr;
2958 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2961 if (ip2 + 1 == (void *) sr2)
2963 sr2->protocol = ip2->protocol;
2964 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2968 ip_ext = (void *) (ip2 + 1);
2969 sr2->protocol = ip_ext->next_hdr;
2970 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2973 if (ip3 + 1 == (void *) sr3)
2975 sr3->protocol = ip3->protocol;
2976 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2980 ip_ext = (void *) (ip3 + 1);
2981 sr3->protocol = ip_ext->next_hdr;
2982 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2987 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2989 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2991 sr_policy_rewrite_trace_t *tr =
2992 vlib_add_trace (vm, node, b0, sizeof (*tr));
2993 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2994 sizeof (tr->src.as_u8));
2995 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2996 sizeof (tr->dst.as_u8));
2999 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3001 sr_policy_rewrite_trace_t *tr =
3002 vlib_add_trace (vm, node, b1, sizeof (*tr));
3003 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3004 sizeof (tr->src.as_u8));
3005 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3006 sizeof (tr->dst.as_u8));
3009 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3011 sr_policy_rewrite_trace_t *tr =
3012 vlib_add_trace (vm, node, b2, sizeof (*tr));
3013 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3014 sizeof (tr->src.as_u8));
3015 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3016 sizeof (tr->dst.as_u8));
3019 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3021 sr_policy_rewrite_trace_t *tr =
3022 vlib_add_trace (vm, node, b3, sizeof (*tr));
3023 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3024 sizeof (tr->src.as_u8));
3025 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3026 sizeof (tr->dst.as_u8));
3030 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3031 n_left_to_next, bi0, bi1, bi2, bi3,
3032 next0, next1, next2, next3);
3035 /* Single loop for potentially the last three packets */
3036 while (n_left_from > 0 && n_left_to_next > 0)
3040 ip6_header_t *ip0 = 0;
3041 ip6_sr_header_t *sr0 = 0;
3043 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3051 n_left_to_next -= 1;
3053 b0 = vlib_get_buffer (vm, bi0);
3055 pool_elt_at_index (sm->sid_lists,
3056 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3057 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3058 vec_len (sl0->rewrite_bsid));
3060 ip0 = vlib_buffer_get_current (b0);
3062 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3064 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3065 ip6_ext_header_len (ip0 + 1));
3067 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3069 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3070 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3071 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3072 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3074 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3076 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3077 ip0->hop_limit -= 1;
3079 clib_net_to_host_u16 (ip0->payload_length) +
3080 vec_len (sl0->rewrite_bsid);
3081 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3083 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3085 ip0->dst_address.as_u64[0] =
3086 (sr0->segments + sr0->segments_left)->as_u64[0];
3087 ip0->dst_address.as_u64[1] =
3088 (sr0->segments + sr0->segments_left)->as_u64[1];
3090 if (ip0 + 1 == (void *) sr0)
3092 sr0->protocol = ip0->protocol;
3093 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3097 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3098 sr0->protocol = ip_ext->next_hdr;
3099 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3102 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3103 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3105 sr_policy_rewrite_trace_t *tr =
3106 vlib_add_trace (vm, node, b0, sizeof (*tr));
3107 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3108 sizeof (tr->src.as_u8));
3109 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3110 sizeof (tr->dst.as_u8));
3115 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3116 n_left_to_next, bi0, next0);
3119 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3122 /* Update counters */
3123 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3124 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3126 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3127 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3129 return from_frame->n_vectors;
3133 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3134 .function = sr_policy_rewrite_b_insert,
3135 .name = "sr-pl-rewrite-b-insert",
3136 .vector_size = sizeof (u32),
3137 .format_trace = format_sr_policy_rewrite_trace,
3138 .type = VLIB_NODE_TYPE_INTERNAL,
3139 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3140 .error_strings = sr_policy_rewrite_error_strings,
3141 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3143 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3144 foreach_sr_policy_rewrite_next
3151 * @brief Function BSID encapsulation
3153 static_always_inline void
3154 end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3155 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3156 u32 *next0, u8 policy_type)
3158 ip6_address_t *new_dst0;
3160 if (PREDICT_FALSE (!sr0))
3161 goto error_bsid_encaps;
3163 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3165 if (PREDICT_TRUE (sr0->segments_left != 0))
3167 sr0->segments_left -= 1;
3168 new_dst0 = (ip6_address_t *) (sr0->segments);
3169 new_dst0 += sr0->segments_left;
3170 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3171 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3174 else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
3179 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3180 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3184 * @brief Graph node for applying a SR policy BSID - Encapsulation
3187 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3188 vlib_frame_t * from_frame)
3190 ip6_sr_main_t *sm = &sr_main;
3191 u32 n_left_from, next_index, *from, *to_next;
3193 from = vlib_frame_vector_args (from_frame);
3194 n_left_from = from_frame->n_vectors;
3196 next_index = node->cached_next_index;
3198 int encap_pkts = 0, bsid_pkts = 0;
3200 while (n_left_from > 0)
3204 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3207 while (n_left_from >= 8 && n_left_to_next >= 4)
3209 u32 bi0, bi1, bi2, bi3;
3210 vlib_buffer_t *b0, *b1, *b2, *b3;
3211 u32 next0, next1, next2, next3;
3212 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3213 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3214 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3215 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3216 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3218 /* Prefetch next iteration. */
3220 vlib_buffer_t *p4, *p5, *p6, *p7;
3222 p4 = vlib_get_buffer (vm, from[4]);
3223 p5 = vlib_get_buffer (vm, from[5]);
3224 p6 = vlib_get_buffer (vm, from[6]);
3225 p7 = vlib_get_buffer (vm, from[7]);
3227 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3228 vlib_prefetch_buffer_header (p4, LOAD);
3229 vlib_prefetch_buffer_header (p5, LOAD);
3230 vlib_prefetch_buffer_header (p6, LOAD);
3231 vlib_prefetch_buffer_header (p7, LOAD);
3233 clib_prefetch_store (p4->data);
3234 clib_prefetch_store (p5->data);
3235 clib_prefetch_store (p6->data);
3236 clib_prefetch_store (p7->data);
3239 to_next[0] = bi0 = from[0];
3240 to_next[1] = bi1 = from[1];
3241 to_next[2] = bi2 = from[2];
3242 to_next[3] = bi3 = from[3];
3246 n_left_to_next -= 4;
3248 b0 = vlib_get_buffer (vm, bi0);
3249 b1 = vlib_get_buffer (vm, bi1);
3250 b2 = vlib_get_buffer (vm, bi2);
3251 b3 = vlib_get_buffer (vm, bi3);
3254 pool_elt_at_index (sm->sid_lists,
3255 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3257 pool_elt_at_index (sm->sid_lists,
3258 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3260 pool_elt_at_index (sm->sid_lists,
3261 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3263 pool_elt_at_index (sm->sid_lists,
3264 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3265 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3266 vec_len (sl0->rewrite));
3267 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3268 vec_len (sl1->rewrite));
3269 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3270 vec_len (sl2->rewrite));
3271 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3272 vec_len (sl3->rewrite));
3274 ip0_encap = vlib_buffer_get_current (b0);
3275 ip1_encap = vlib_buffer_get_current (b1);
3276 ip2_encap = vlib_buffer_get_current (b2);
3277 ip3_encap = vlib_buffer_get_current (b3);
3280 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3283 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3286 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3289 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3292 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3294 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3296 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3298 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3301 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3302 sl0->rewrite, vec_len (sl0->rewrite));
3303 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3304 sl1->rewrite, vec_len (sl1->rewrite));
3305 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3306 sl2->rewrite, vec_len (sl2->rewrite));
3307 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3308 sl3->rewrite, vec_len (sl3->rewrite));
3310 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3311 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3312 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3313 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3315 ip0 = vlib_buffer_get_current (b0);
3316 ip1 = vlib_buffer_get_current (b1);
3317 ip2 = vlib_buffer_get_current (b2);
3318 ip3 = vlib_buffer_get_current (b3);
3320 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3321 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3322 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3323 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
3325 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3327 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3329 sr_policy_rewrite_trace_t *tr =
3330 vlib_add_trace (vm, node, b0, sizeof (*tr));
3331 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3332 sizeof (tr->src.as_u8));
3333 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3334 sizeof (tr->dst.as_u8));
3337 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3339 sr_policy_rewrite_trace_t *tr =
3340 vlib_add_trace (vm, node, b1, sizeof (*tr));
3341 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3342 sizeof (tr->src.as_u8));
3343 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3344 sizeof (tr->dst.as_u8));
3347 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3349 sr_policy_rewrite_trace_t *tr =
3350 vlib_add_trace (vm, node, b2, sizeof (*tr));
3351 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3352 sizeof (tr->src.as_u8));
3353 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3354 sizeof (tr->dst.as_u8));
3357 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3359 sr_policy_rewrite_trace_t *tr =
3360 vlib_add_trace (vm, node, b3, sizeof (*tr));
3361 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3362 sizeof (tr->src.as_u8));
3363 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3364 sizeof (tr->dst.as_u8));
3369 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3370 n_left_to_next, bi0, bi1, bi2, bi3,
3371 next0, next1, next2, next3);
3374 /* Single loop for potentially the last three packets */
3375 while (n_left_from > 0 && n_left_to_next > 0)
3379 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3380 ip6_sr_header_t *sr0;
3382 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3389 n_left_to_next -= 1;
3390 b0 = vlib_get_buffer (vm, bi0);
3393 pool_elt_at_index (sm->sid_lists,
3394 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3395 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3396 vec_len (sl0->rewrite));
3398 ip0_encap = vlib_buffer_get_current (b0);
3400 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3402 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3405 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3406 sl0->rewrite, vec_len (sl0->rewrite));
3407 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3409 ip0 = vlib_buffer_get_current (b0);
3411 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3413 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3414 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3416 sr_policy_rewrite_trace_t *tr =
3417 vlib_add_trace (vm, node, b0, sizeof (*tr));
3418 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3419 sizeof (tr->src.as_u8));
3420 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3421 sizeof (tr->dst.as_u8));
3425 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3426 n_left_to_next, bi0, next0);
3429 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3432 /* Update counters */
3433 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3434 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3436 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3437 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3440 return from_frame->n_vectors;
3444 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3445 .function = sr_policy_rewrite_b_encaps,
3446 .name = "sr-pl-rewrite-b-encaps",
3447 .vector_size = sizeof (u32),
3448 .format_trace = format_sr_policy_rewrite_trace,
3449 .type = VLIB_NODE_TYPE_INTERNAL,
3450 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3451 .error_strings = sr_policy_rewrite_error_strings,
3452 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3454 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3455 foreach_sr_policy_rewrite_next
3461 /*************************** SR Policy plugins ******************************/
3463 * @brief SR Policy plugin registry
3466 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3467 u8 * keyword_str, u8 * def_str,
3468 u8 * params_str, u8 prefix_length,
3470 format_function_t * ls_format,
3471 unformat_function_t * ls_unformat,
3472 sr_p_plugin_callback_t * creation_fn,
3473 sr_p_plugin_callback_t * removal_fn)
3475 ip6_sr_main_t *sm = &sr_main;
3478 sr_policy_fn_registration_t *plugin;
3480 /* Did this function exist? If so update it */
3481 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3484 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3486 /* Else create a new one and set hash key */
3489 pool_get (sm->policy_plugin_functions, plugin);
3490 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3491 plugin - sm->policy_plugin_functions);
3494 clib_memset (plugin, 0, sizeof (*plugin));
3496 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3497 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3498 plugin->prefix_length = prefix_length;
3499 plugin->ls_format = ls_format;
3500 plugin->ls_unformat = ls_unformat;
3501 plugin->creation = creation_fn;
3502 plugin->removal = removal_fn;
3503 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3504 plugin->function_name = format (0, "%s%c", fn_name, 0);
3505 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3506 plugin->def_str = format (0, "%s%c", def_str, 0);
3507 plugin->params_str = format (0, "%s%c", params_str, 0);
3509 return plugin->sr_policy_function_number;
3513 * @brief CLI function to 'show' all available SR LocalSID behaviors
3515 static clib_error_t *
3516 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3517 unformat_input_t * input,
3518 vlib_cli_command_t * cmd)
3520 ip6_sr_main_t *sm = &sr_main;
3521 sr_policy_fn_registration_t *plugin;
3522 sr_policy_fn_registration_t **plugins_vec = 0;
3525 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3528 pool_foreach (plugin, sm->policy_plugin_functions)
3529 { vec_add1 (plugins_vec, plugin); }
3532 vlib_cli_output (vm, "Plugin behaviors:\n");
3533 for (i = 0; i < vec_len (plugins_vec); i++)
3535 plugin = plugins_vec[i];
3536 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3538 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3544 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3545 .path = "show sr policy behaviors",
3546 .short_help = "show sr policy behaviors",
3547 .function = show_sr_policy_behaviors_command_fn,
3551 /*************************** SR Segment Lists DPOs ****************************/
3553 format_sr_segment_list_dpo (u8 * s, va_list * args)
3555 ip6_sr_main_t *sm = &sr_main;
3556 ip6_address_t *addr;
3559 index_t index = va_arg (*args, index_t);
3560 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3561 s = format (s, "SR: Segment List index:[%d]", index);
3562 s = format (s, "\n\tSegments:");
3564 sl = pool_elt_at_index (sm->sid_lists, index);
3566 s = format (s, "< ");
3567 vec_foreach (addr, sl->segments)
3569 s = format (s, "%U, ", format_ip6_address, addr);
3571 s = format (s, "\b\b > - ");
3572 s = format (s, "Weight: %u", sl->weight);
3577 const static dpo_vft_t sr_policy_rewrite_vft = {
3578 .dv_lock = sr_dpo_lock,
3579 .dv_unlock = sr_dpo_unlock,
3580 .dv_format = format_sr_segment_list_dpo,
3583 const static char *const sr_pr_encaps_ip6_nodes[] = {
3584 "sr-pl-rewrite-encaps",
3588 const static char *const sr_pr_encaps_ip4_nodes[] = {
3589 "sr-pl-rewrite-encaps-v4",
3593 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3594 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3595 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3598 const static char *const sr_pr_insert_ip6_nodes[] = {
3599 "sr-pl-rewrite-insert",
3603 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3604 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3607 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3608 "sr-pl-rewrite-b-insert",
3612 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3613 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3616 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3617 "sr-pl-rewrite-b-encaps",
3621 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3622 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3625 /********************* SR Policy Rewrite initialization ***********************/
3627 * @brief SR Policy Rewrite initialization
3630 sr_policy_rewrite_init (vlib_main_t * vm)
3632 ip6_sr_main_t *sm = &sr_main;
3634 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3635 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3636 sizeof (ip6_address_t));
3638 /* Init SR VPO DPOs type */
3639 sr_pr_encaps_dpo_type =
3640 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3642 sr_pr_insert_dpo_type =
3643 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3645 sr_pr_bsid_encaps_dpo_type =
3646 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3648 sr_pr_bsid_insert_dpo_type =
3649 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3651 /* Register the L2 encaps node used in HW redirect */
3652 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3654 sm->fib_table_ip6 = (u32) ~ 0;
3655 sm->fib_table_ip4 = (u32) ~ 0;
3660 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3664 * fd.io coding-style-patch-verification: ON
3667 * eval: (c-set-style "gnu")