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>
50 #include <vnet/srv6/sr_pt.h>
52 #include <vppinfra/byte_order.h>
53 #include <vppinfra/error.h>
54 #include <vppinfra/elog.h>
57 * @brief SR policy rewrite trace
61 ip6_address_t src, dst;
62 } sr_policy_rewrite_trace_t;
65 #define foreach_sr_policy_rewrite_next \
66 _(IP6_LOOKUP, "ip6-lookup") \
67 _(ERROR, "error-drop")
71 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
72 foreach_sr_policy_rewrite_next
74 SR_POLICY_REWRITE_N_NEXT,
75 } sr_policy_rewrite_next_t;
77 /* SR rewrite errors */
78 #define foreach_sr_policy_rewrite_error \
79 _(INTERNAL_ERROR, "Segment Routing undefined error") \
80 _(BSID_ZERO, "BSID with SL = 0") \
81 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
82 _(COUNTER_ENCAP, "SR: Encaps packets") \
83 _(COUNTER_INSERT, "SR: SRH inserted packets") \
84 _(COUNTER_BSID, "SR: BindingSID steered packets")
88 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
89 foreach_sr_policy_rewrite_error
91 SR_POLICY_REWRITE_N_ERROR,
92 } sr_policy_rewrite_error_t;
94 static char *sr_policy_rewrite_error_strings[] = {
95 #define _(sym,string) string,
96 foreach_sr_policy_rewrite_error
101 * @brief Dynamically added SR SL DPO type
103 static dpo_type_t sr_pr_encaps_dpo_type;
104 static dpo_type_t sr_pr_insert_dpo_type;
105 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
106 static dpo_type_t sr_pr_bsid_insert_dpo_type;
109 * @brief IPv6 SA for encapsulated packets
111 static ip6_address_t sr_pr_encaps_src;
112 static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
114 /******************* SR rewrite set encaps IPv6 source addr *******************/
115 /* Note: This is temporal. We don't know whether to follow this path or
116 take the ip address of a loopback interface or even the OIF */
119 sr_set_source (ip6_address_t * address)
121 clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
125 sr_get_encaps_source ()
127 return &sr_pr_encaps_src;
130 static clib_error_t *
131 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
132 vlib_cli_command_t * cmd)
134 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
137 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
140 return clib_error_return (0, "No address specified");
142 return clib_error_return (0, "No address specified");
146 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
147 .path = "set sr encaps source",
148 .short_help = "set sr encaps source addr <ip6_addr>",
149 .function = set_sr_src_command_fn,
153 /******************** SR rewrite set encaps IPv6 hop-limit ********************/
156 sr_set_hop_limit (u8 hop_limit)
158 sr_pr_encaps_hop_limit = hop_limit;
162 sr_get_hop_limit (void)
164 return sr_pr_encaps_hop_limit;
167 static clib_error_t *
168 set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
169 vlib_cli_command_t * cmd)
171 int hop_limit = sr_get_hop_limit ();
173 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
174 return clib_error_return (0, "No value specified");
175 if (!unformat (input, "%d", &hop_limit))
176 return clib_error_return (0, "Invalid value");
177 if (hop_limit <= 0 || hop_limit > 255)
178 return clib_error_return (0, "Value out of range [1-255]");
179 sr_pr_encaps_hop_limit = (u8) hop_limit;
184 VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
185 .path = "set sr encaps hop-limit",
186 .short_help = "set sr encaps hop-limit <value>",
187 .function = set_sr_hop_limit_command_fn,
191 /*********************** SR rewrite string computation ************************/
193 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
195 * @param sl is a vector of IPv6 addresses composing the Segment List
197 * @return precomputed rewrite string for encapsulation
200 compute_rewrite_encaps (ip6_address_t *sl, u8 type)
203 ip6_sr_header_t *srh;
204 ip6_sr_pt_tlv_t *srh_pt_tlv;
205 ip6_address_t *addrp, *this_address;
206 u32 header_length = 0;
210 header_length += IPv6_DEFAULT_HEADER_LENGTH;
211 if (type == SR_POLICY_TYPE_TEF)
213 header_length += sizeof (ip6_sr_header_t);
214 header_length += vec_len (sl) * sizeof (ip6_address_t);
215 header_length += sizeof (ip6_sr_pt_tlv_t);
217 else if (vec_len (sl) > 1)
219 header_length += sizeof (ip6_sr_header_t);
220 header_length += vec_len (sl) * sizeof (ip6_address_t);
223 vec_validate (rs, header_length - 1);
225 iph = (ip6_header_t *) rs;
226 iph->ip_version_traffic_class_and_flow_label =
227 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
228 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
229 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
230 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
231 iph->protocol = IP_PROTOCOL_IPV6;
232 iph->hop_limit = sr_pr_encaps_hop_limit;
234 if (type == SR_POLICY_TYPE_TEF)
236 srh = (ip6_sr_header_t *) (iph + 1);
237 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
238 srh->protocol = IP_PROTOCOL_IPV6;
239 srh->type = ROUTING_HEADER_TYPE_SR;
242 srh->segments_left = vec_len (sl) - 1;
243 srh->last_entry = vec_len (sl) - 1;
245 ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
246 sizeof (ip6_sr_pt_tlv_t)) /
249 addrp = srh->segments + vec_len (sl) - 1;
250 vec_foreach (this_address, sl)
252 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
253 sizeof (ip6_address_t));
256 srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
257 srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
258 srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
260 else if (vec_len (sl) > 1)
262 srh = (ip6_sr_header_t *) (iph + 1);
263 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
264 srh->protocol = IP_PROTOCOL_IPV6;
265 srh->type = ROUTING_HEADER_TYPE_SR;
266 srh->segments_left = vec_len (sl) - 1;
267 srh->last_entry = vec_len (sl) - 1;
268 srh->length = ((sizeof (ip6_sr_header_t) +
269 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
272 addrp = srh->segments + vec_len (sl) - 1;
273 vec_foreach (this_address, sl)
275 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
276 sizeof (ip6_address_t));
280 iph->dst_address.as_u64[0] = sl->as_u64[0];
281 iph->dst_address.as_u64[1] = sl->as_u64[1];
286 * @brief SR rewrite string computation for SRH insertion (inline)
288 * @param sl is a vector of IPv6 addresses composing the Segment List
290 * @return precomputed rewrite string for SRH insertion
293 compute_rewrite_insert (ip6_address_t *sl, u8 type)
295 ip6_sr_header_t *srh;
296 ip6_address_t *addrp, *this_address;
297 u32 header_length = 0;
301 header_length += sizeof (ip6_sr_header_t);
302 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
304 vec_validate (rs, header_length - 1);
306 srh = (ip6_sr_header_t *) rs;
307 srh->type = ROUTING_HEADER_TYPE_SR;
308 srh->segments_left = vec_len (sl);
309 srh->last_entry = vec_len (sl);
310 srh->length = ((sizeof (ip6_sr_header_t) +
311 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
314 addrp = srh->segments + vec_len (sl);
315 vec_foreach (this_address, sl)
317 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
318 sizeof (ip6_address_t));
325 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
327 * @param sl is a vector of IPv6 addresses composing the Segment List
329 * @return precomputed rewrite string for SRH insertion with BSID
332 compute_rewrite_bsid (ip6_address_t * sl)
334 ip6_sr_header_t *srh;
335 ip6_address_t *addrp, *this_address;
336 u32 header_length = 0;
340 header_length += sizeof (ip6_sr_header_t);
341 header_length += vec_len (sl) * sizeof (ip6_address_t);
343 vec_validate (rs, header_length - 1);
345 srh = (ip6_sr_header_t *) rs;
346 srh->type = ROUTING_HEADER_TYPE_SR;
347 srh->segments_left = vec_len (sl) - 1;
348 srh->last_entry = vec_len (sl) - 1;
349 srh->length = ((sizeof (ip6_sr_header_t) +
350 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
353 addrp = srh->segments + vec_len (sl) - 1;
354 vec_foreach (this_address, sl)
356 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
357 sizeof (ip6_address_t));
363 /*************************** SR LB helper functions **************************/
365 * @brief Creates a Segment List and adds it to an SR policy
367 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
368 * not necessarily unique. Hence there might be two Segment List within the
369 * same SR Policy with exactly the same segments and same weight.
371 * @param sr_policy is the SR policy where the SL will be added
372 * @param sl is a vector of IPv6 addresses composing the Segment List
373 * @param weight is the weight of the SegmentList (for load-balancing purposes)
374 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
376 * @return pointer to the just created segment list
378 static inline ip6_sr_sl_t *
379 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
382 ip6_sr_main_t *sm = &sr_main;
383 ip6_sr_sl_t *segment_list;
384 sr_policy_fn_registration_t *plugin = 0;
386 pool_get (sm->sid_lists, segment_list);
387 clib_memset (segment_list, 0, sizeof (*segment_list));
389 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
391 /* Fill in segment list */
392 segment_list->weight =
393 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
395 segment_list->segments = vec_dup (sl);
396 segment_list->policy_type = sr_policy->type;
398 segment_list->egress_fib_table =
399 ip6_fib_index_from_table_id (sr_policy->fib_table);
403 segment_list->rewrite = compute_rewrite_encaps (sl, sr_policy->type);
404 segment_list->rewrite_bsid = segment_list->rewrite;
408 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
409 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
412 if (sr_policy->plugin)
415 pool_elt_at_index (sm->policy_plugin_functions,
416 sr_policy->plugin - SR_BEHAVIOR_LAST);
418 segment_list->plugin = sr_policy->plugin;
419 segment_list->plugin_mem = sr_policy->plugin_mem;
421 plugin->creation (sr_policy);
425 dpo_reset (&segment_list->bsid_dpo);
426 dpo_reset (&segment_list->ip6_dpo);
427 dpo_reset (&segment_list->ip4_dpo);
431 if (!sr_policy->plugin)
433 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
434 DPO_PROTO_IP6, segment_list - sm->sid_lists);
435 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
436 DPO_PROTO_IP4, segment_list - sm->sid_lists);
437 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
438 DPO_PROTO_IP6, segment_list - sm->sid_lists);
442 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
443 segment_list - sm->sid_lists);
444 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
445 segment_list - sm->sid_lists);
446 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
447 segment_list - sm->sid_lists);
452 if (!sr_policy->plugin)
454 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
455 DPO_PROTO_IP6, segment_list - sm->sid_lists);
456 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
457 DPO_PROTO_IP6, segment_list - sm->sid_lists);
461 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
462 segment_list - sm->sid_lists);
463 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
464 segment_list - sm->sid_lists);
472 * @brief Updates the Load-Balancer after an SR Policy change
474 * @param sr_policy is the modified SR Policy
477 update_lb (ip6_sr_policy_t * sr_policy)
479 flow_hash_config_t fhc;
481 ip6_sr_sl_t *segment_list;
482 ip6_sr_main_t *sm = &sr_main;
483 load_balance_path_t path;
484 path.path_index = FIB_NODE_INDEX_INVALID;
485 load_balance_path_t *ip4_path_vector = 0;
486 load_balance_path_t *ip6_path_vector = 0;
487 load_balance_path_t *b_path_vector = 0;
489 /* In case LB does not exist, create it */
490 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
493 .fp_proto = FIB_PROTOCOL_IP6,
496 .ip6 = sr_policy->bsid,
500 /* Add FIB entry for BSID */
501 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
504 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
505 load_balance_create (0, DPO_PROTO_IP6, fhc));
507 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
508 load_balance_create (0, DPO_PROTO_IP6, fhc));
510 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
511 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
512 sr_policy->fib_table),
514 FIB_ENTRY_FLAG_EXCLUSIVE,
515 &sr_policy->bsid_dpo);
517 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
520 FIB_ENTRY_FLAG_EXCLUSIVE,
521 &sr_policy->ip6_dpo);
523 if (sr_policy->is_encap)
525 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
526 load_balance_create (0, DPO_PROTO_IP4, fhc));
528 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
531 FIB_ENTRY_FLAG_EXCLUSIVE,
532 &sr_policy->ip4_dpo);
537 /* Create the LB path vector */
538 vec_foreach (sl_index, sr_policy->segments_lists)
540 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
541 path.path_dpo = segment_list->bsid_dpo;
542 path.path_weight = segment_list->weight;
543 vec_add1 (b_path_vector, path);
544 path.path_dpo = segment_list->ip6_dpo;
545 vec_add1 (ip6_path_vector, path);
546 if (sr_policy->is_encap)
548 path.path_dpo = segment_list->ip4_dpo;
549 vec_add1 (ip4_path_vector, path);
553 /* Update LB multipath */
554 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
555 LOAD_BALANCE_FLAG_NONE);
556 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
557 LOAD_BALANCE_FLAG_NONE);
558 if (sr_policy->is_encap)
559 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
560 LOAD_BALANCE_FLAG_NONE);
563 vec_free (b_path_vector);
564 vec_free (ip6_path_vector);
565 vec_free (ip4_path_vector);
569 * @brief Updates the Replicate DPO after an SR Policy change
571 * @param sr_policy is the modified SR Policy (type spray)
574 update_replicate (ip6_sr_policy_t * sr_policy)
577 ip6_sr_sl_t *segment_list;
578 ip6_sr_main_t *sm = &sr_main;
579 load_balance_path_t path;
580 path.path_index = FIB_NODE_INDEX_INVALID;
581 load_balance_path_t *b_path_vector = 0;
582 load_balance_path_t *ip6_path_vector = 0;
583 load_balance_path_t *ip4_path_vector = 0;
585 /* In case LB does not exist, create it */
586 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
588 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
589 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
591 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
592 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
594 /* Update FIB entry's DPO to point to SR without LB */
596 .fp_proto = FIB_PROTOCOL_IP6,
599 .ip6 = sr_policy->bsid,
602 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
603 sr_policy->fib_table),
605 FIB_ENTRY_FLAG_EXCLUSIVE,
606 &sr_policy->bsid_dpo);
608 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
611 FIB_ENTRY_FLAG_EXCLUSIVE,
612 &sr_policy->ip6_dpo);
614 if (sr_policy->is_encap)
616 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
617 replicate_create (0, DPO_PROTO_IP4));
619 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
622 FIB_ENTRY_FLAG_EXCLUSIVE,
623 &sr_policy->ip4_dpo);
628 /* Create the replicate path vector */
629 path.path_weight = 1;
630 vec_foreach (sl_index, sr_policy->segments_lists)
632 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
633 path.path_dpo = segment_list->bsid_dpo;
634 vec_add1 (b_path_vector, path);
635 path.path_dpo = segment_list->ip6_dpo;
636 vec_add1 (ip6_path_vector, path);
637 if (sr_policy->is_encap)
639 path.path_dpo = segment_list->ip4_dpo;
640 vec_add1 (ip4_path_vector, path);
644 /* Update replicate multipath */
645 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
646 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
647 if (sr_policy->is_encap)
648 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
651 /******************************* SR rewrite API *******************************/
652 /* Three functions for handling sr policies:
656 * All of them are API. CLI function on sr_policy_command_fn */
659 * @brief Create a new SR policy
661 * @param bsid is the bindingSID of the SR Policy
662 * @param segments is a vector of IPv6 address composing the segment list
663 * @param weight is the weight of the sid list. optional.
664 * @param behavior is the behavior of the SR policy. (default//spray)
665 * @param fib_table is the VRF where to install the FIB entry for the BSID
666 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
668 * @return 0 if correct, else error
671 sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments, u32 weight,
672 u8 type, u32 fib_table, u8 is_encap, u16 plugin,
675 ip6_sr_main_t *sm = &sr_main;
676 ip6_sr_policy_t *sr_policy = 0;
679 /* Search for existing keys (BSID) */
680 p = mhash_get (&sm->sr_policies_index_hash, bsid);
683 /* Add SR policy that already exists; complain */
687 /* Search collision in FIB entries */
688 /* Explanation: It might be possible that some other entity has already
689 * created a route for the BSID. This in theory is impossible, but in
690 * practise we could see it. Assert it and scream if needed */
692 .fp_proto = FIB_PROTOCOL_IP6,
699 /* Lookup the FIB index associated to the table selected */
700 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
701 (fib_table != (u32) ~ 0 ? fib_table : 0));
705 /* Lookup whether there exists an entry for the BSID */
706 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
707 if (FIB_NODE_INDEX_INVALID != fei)
708 return -12; //There is an entry for such lookup
710 /* Add an SR policy object */
711 pool_get (sm->sr_policies, sr_policy);
712 clib_memset (sr_policy, 0, sizeof (*sr_policy));
713 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
714 sr_policy->type = type;
715 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
716 sr_policy->is_encap = is_encap;
720 sr_policy->plugin = plugin;
721 sr_policy->plugin_mem = ls_plugin_mem;
725 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
728 /* Create a segment list and add the index to the SR policy */
729 create_sl (sr_policy, segments, weight, is_encap);
731 /* If FIB doesnt exist, create them */
732 if (sm->fib_table_ip6 == (u32) ~ 0)
734 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
736 "SRv6 steering of IP6 prefixes through BSIDs");
737 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
739 "SRv6 steering of IP4 prefixes through BSIDs");
742 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
743 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
744 sr_policy->type == SR_POLICY_TYPE_TEF)
745 update_lb (sr_policy);
746 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
747 update_replicate (sr_policy);
752 * @brief Delete a SR policy
754 * @param bsid is the bindingSID of the SR Policy
755 * @param index is the index of the SR policy
757 * @return 0 if correct, else error
760 sr_policy_del (ip6_address_t * bsid, u32 index)
762 ip6_sr_main_t *sm = &sr_main;
763 ip6_sr_policy_t *sr_policy = 0;
764 ip6_sr_sl_t *segment_list;
770 p = mhash_get (&sm->sr_policies_index_hash, bsid);
772 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
778 sr_policy = pool_elt_at_index (sm->sr_policies, index);
781 /* Remove BindingSID FIB entry */
783 .fp_proto = FIB_PROTOCOL_IP6,
786 .ip6 = sr_policy->bsid,
791 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
792 sr_policy->fib_table),
793 &pfx, FIB_SOURCE_SR);
795 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
797 if (sr_policy->is_encap)
798 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
800 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
802 dpo_reset (&sr_policy->bsid_dpo);
803 dpo_reset (&sr_policy->ip4_dpo);
804 dpo_reset (&sr_policy->ip6_dpo);
807 /* Clean SID Lists */
808 vec_foreach (sl_index, sr_policy->segments_lists)
810 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
811 vec_free (segment_list->segments);
812 vec_free (segment_list->rewrite);
813 if (!sr_policy->is_encap)
814 vec_free (segment_list->rewrite_bsid);
815 pool_put_index (sm->sid_lists, *sl_index);
818 if (sr_policy->plugin)
820 sr_policy_fn_registration_t *plugin = 0;
823 pool_elt_at_index (sm->policy_plugin_functions,
824 sr_policy->plugin - SR_BEHAVIOR_LAST);
826 plugin->removal (sr_policy);
827 sr_policy->plugin = 0;
828 sr_policy->plugin_mem = NULL;
831 /* Remove SR policy entry */
832 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
833 pool_put (sm->sr_policies, sr_policy);
835 /* If FIB empty unlock it */
836 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
838 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
839 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
840 sm->fib_table_ip6 = (u32) ~ 0;
841 sm->fib_table_ip4 = (u32) ~ 0;
848 * @brief Modify an existing SR policy
850 * The possible modifications are adding a new Segment List, modifying an
851 * existing Segment List (modify the weight only) and delete a given
852 * Segment List from the SR Policy.
854 * @param bsid is the bindingSID of the SR Policy
855 * @param index is the index of the SR policy
856 * @param fib_table is the VRF where to install the FIB entry for the BSID
857 * @param operation is the operation to perform (among the top ones)
858 * @param segments is a vector of IPv6 address composing the segment list
859 * @param sl_index is the index of the Segment List to modify/delete
860 * @param weight is the weight of the sid list. optional.
861 * @param is_encap Mode. Encapsulation or SRH insertion.
863 * @return 0 if correct, else error
866 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
867 u8 operation, ip6_address_t * segments, u32 sl_index,
870 ip6_sr_main_t *sm = &sr_main;
871 ip6_sr_policy_t *sr_policy = 0;
872 ip6_sr_sl_t *segment_list;
873 u32 *sl_index_iterate;
878 p = mhash_get (&sm->sr_policies_index_hash, bsid);
880 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
886 sr_policy = pool_elt_at_index (sm->sr_policies, index);
889 if (operation == 1) /* Add SR List to an existing SR policy */
891 /* Create the new SL */
893 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
895 /* Create a new LB DPO */
896 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
897 update_lb (sr_policy);
898 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
899 update_replicate (sr_policy);
901 else if (operation == 2) /* Delete SR List from an existing SR policy */
903 /* Check that currently there are more than one SID list */
904 if (vec_len (sr_policy->segments_lists) == 1)
907 /* Check that the SR list does exist and is assigned to the sr policy */
908 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
909 if (*sl_index_iterate == sl_index)
912 if (*sl_index_iterate != sl_index)
915 /* Remove the lucky SR list that is being kicked out */
916 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
917 vec_free (segment_list->segments);
918 vec_free (segment_list->rewrite);
919 if (!sr_policy->is_encap)
920 vec_free (segment_list->rewrite_bsid);
921 pool_put_index (sm->sid_lists, sl_index);
922 vec_del1 (sr_policy->segments_lists,
923 sl_index_iterate - sr_policy->segments_lists);
925 /* Create a new LB DPO */
926 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
927 update_lb (sr_policy);
928 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
929 update_replicate (sr_policy);
931 else if (operation == 3) /* Modify the weight of an existing SR List */
933 /* Find the corresponding SL */
934 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
935 if (*sl_index_iterate == sl_index)
938 if (*sl_index_iterate != sl_index)
941 /* Change the weight */
942 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
943 segment_list->weight = weight;
946 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
947 update_lb (sr_policy);
949 else /* Incorrect op. */
956 * @brief CLI for 'sr policies' command family
958 static clib_error_t *
959 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
960 vlib_cli_command_t * cmd)
962 ip6_sr_main_t *sm = &sr_main;
964 char is_del = 0, is_add = 0, is_mod = 0;
966 ip6_address_t bsid, next_address;
967 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
968 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
969 ip6_address_t *segments = 0, *this_seg;
972 u8 type = SR_POLICY_TYPE_DEFAULT;
974 void *ls_plugin_mem = 0;
976 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
978 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
980 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
982 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
985 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
987 else if (!is_add && !policy_set
988 && unformat (input, "index %d", &sr_policy_index))
990 else if (unformat (input, "weight %d", &weight));
992 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
994 vec_add2 (segments, this_seg, 1);
995 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
998 else if (unformat (input, "add sl"))
1000 else if (unformat (input, "del sl index %d", &sl_index))
1002 else if (unformat (input, "mod sl index %d", &sl_index))
1004 else if (fib_table == (u32) ~ 0
1005 && unformat (input, "fib-table %d", &fib_table));
1006 else if (unformat (input, "encap"))
1008 else if (unformat (input, "insert"))
1010 else if (unformat (input, "spray"))
1011 type = SR_POLICY_TYPE_SPRAY;
1012 else if (unformat (input, "tef"))
1013 type = SR_POLICY_TYPE_TEF;
1014 else if (!behavior && unformat (input, "behavior"))
1016 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
1017 sr_policy_fn_registration_t **plugin_it = 0;
1020 pool_foreach (plugin, sm->policy_plugin_functions)
1022 vec_add1 (vec_plugins, plugin);
1026 vec_foreach (plugin_it, vec_plugins)
1029 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
1031 behavior = (*plugin_it)->sr_policy_function_number;
1038 return clib_error_return (0, "Invalid behavior");
1045 if (!is_add && !is_mod && !is_del)
1046 return clib_error_return (0, "Incorrect CLI");
1049 return clib_error_return (0, "No SR policy BSID or index specified");
1053 if (behavior && vec_len (segments) == 0)
1055 vec_add2 (segments, this_seg, 1);
1056 clib_memset (this_seg, 0, sizeof (*this_seg));
1059 if (vec_len (segments) == 0)
1060 return clib_error_return (0, "No Segment List specified");
1062 rv = sr_policy_add (&bsid, segments, weight, type, fib_table, is_encap,
1063 behavior, ls_plugin_mem);
1065 vec_free (segments);
1068 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1073 return clib_error_return (0, "No SL modification specified");
1074 if (operation != 1 && sl_index == (u32) ~ 0)
1075 return clib_error_return (0, "No Segment List index specified");
1076 if (operation == 1 && vec_len (segments) == 0)
1077 return clib_error_return (0, "No Segment List specified");
1078 if (operation == 3 && weight == (u32) ~ 0)
1079 return clib_error_return (0, "No new weight for the SL specified");
1081 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1082 sr_policy_index, fib_table, operation, segments,
1086 vec_free (segments);
1096 return clib_error_return (0,
1097 "There is already a FIB entry for the BindingSID address.\n"
1098 "The SR policy could not be created.");
1100 return clib_error_return (0, "The specified FIB table does not exist.");
1102 return clib_error_return (0,
1103 "The selected SR policy only contains ONE segment list. "
1104 "Please remove the SR policy instead");
1106 return clib_error_return (0,
1107 "Could not delete the segment list. "
1108 "It is not associated with that SR policy.");
1110 return clib_error_return (0,
1111 "Could not modify the segment list. "
1112 "The given SL is not associated with such SR policy.");
1114 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1120 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1121 .path = "sr policy",
1122 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1123 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1125 "Manipulation of SR policies.\n"
1126 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1127 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1128 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1129 "Each SR policy will be associated with a unique BindingSID.\n"
1130 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1131 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1132 "The add command will create a SR policy with its first segment list (sl)\n"
1133 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1134 "within an SR policy.\n"
1135 "The del command allows you to delete a SR policy along with all its associated\n"
1137 .function = sr_policy_command_fn,
1142 * @brief CLI to display onscreen all the SR policies
1144 static clib_error_t *
1145 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1146 vlib_cli_command_t * cmd)
1148 ip6_sr_main_t *sm = &sr_main;
1150 ip6_sr_sl_t *segment_list = 0;
1151 ip6_sr_policy_t *sr_policy = 0;
1152 ip6_sr_policy_t **vec_policies = 0;
1153 ip6_address_t *addr;
1157 vlib_cli_output (vm, "SR policies:");
1160 pool_foreach (sr_policy, sm->sr_policies)
1161 {vec_add1 (vec_policies, sr_policy); }
1164 vec_foreach_index (i, vec_policies)
1166 sr_policy = vec_policies[i];
1167 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1168 (u32) (sr_policy - sm->sr_policies),
1169 format_ip6_address, &sr_policy->bsid);
1170 vlib_cli_output (vm, "\tBehavior: %s",
1171 (sr_policy->is_encap ? "Encapsulation" :
1173 switch (sr_policy->type)
1175 case SR_POLICY_TYPE_SPRAY:
1176 vlib_cli_output (vm, "\tType: %s", "Spray");
1178 case SR_POLICY_TYPE_TEF:
1179 vlib_cli_output (vm, "\tType: %s",
1180 "TEF (Timestamp, Encapsulate, and Forward)");
1183 vlib_cli_output (vm, "\tType: %s", "Default");
1186 vlib_cli_output (vm, "\tFIB table: %u",
1187 (sr_policy->fib_table !=
1188 (u32) ~ 0 ? sr_policy->fib_table : 0));
1189 vlib_cli_output (vm, "\tSegment Lists:");
1190 vec_foreach (sl_index, sr_policy->segments_lists)
1193 s = format (s, "\t[%u].- ", *sl_index);
1194 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1195 s = format (s, "< ");
1196 vec_foreach (addr, segment_list->segments)
1198 s = format (s, "%U, ", format_ip6_address, addr);
1200 s = format (s, "\b\b > ");
1201 s = format (s, "weight: %u", segment_list->weight);
1202 vlib_cli_output (vm, " %v", s);
1204 vlib_cli_output (vm, "-----------");
1210 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1211 .path = "show sr policies",
1212 .short_help = "show sr policies",
1213 .function = show_sr_policies_command_fn,
1218 * @brief CLI to display onscreen the SR encaps source addr
1220 static clib_error_t *
1221 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1222 vlib_cli_command_t * cmd)
1224 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1225 sr_get_encaps_source ());
1231 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1232 .path = "show sr encaps source addr",
1233 .short_help = "show sr encaps source addr",
1234 .function = show_sr_encaps_source_command_fn,
1239 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1241 static clib_error_t *
1242 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1243 unformat_input_t * input,
1244 vlib_cli_command_t * cmd)
1246 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1252 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1253 .path = "show sr encaps hop-limit",
1254 .short_help = "show sr encaps hop-limit",
1255 .function = show_sr_encaps_hop_limit_command_fn,
1259 /*************************** SR rewrite graph node ****************************/
1261 * @brief Trace for the SR Policy Rewrite graph node
1264 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1267 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1268 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1269 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1272 (s, "SR-policy-rewrite: src %U dst %U",
1273 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1278 * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
1280 static_always_inline void
1281 srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1284 ip6_sr_header_t *srh;
1285 ip6_sr_pt_tlv_t *srh_pt_tlv;
1287 sr_pt_iface_t *ls = 0;
1289 srh = (ip6_sr_header_t *) (ip0 + 1);
1292 (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
1293 sizeof (ip6_sr_header_t) +
1294 sizeof (ip6_address_t) * (srh->last_entry + 1));
1296 unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
1297 srh_pt_tlv->t64.sec = clib_host_to_net_u32 (ts.sec);
1298 srh_pt_tlv->t64.nsec = clib_host_to_net_u32 (ts.nsec);
1299 ls = sr_pt_find_iface (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1302 id_ld = ls->id << 4;
1303 id_ld |= ls->ingress_load;
1304 srh_pt_tlv->id_ld = clib_host_to_net_u16 (id_ld);
1309 * @brief IPv6 encapsulation processing as per RFC2473
1311 static_always_inline void
1312 encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1313 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1319 ip0_encap->hop_limit -= 1;
1321 ip0->payload_length + sizeof (ip6_header_t) +
1322 clib_net_to_host_u16 (ip0_encap->payload_length);
1323 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1325 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1326 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1328 (clib_net_to_host_u32 (
1329 ip0_encap->ip_version_traffic_class_and_flow_label) &
1331 (flow_label & 0x0000ffff));
1332 if (policy_type == SR_POLICY_TYPE_TEF)
1333 srv6_tef_behavior (node, b0, ip0);
1337 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1340 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1341 vlib_frame_t * from_frame)
1343 ip6_sr_main_t *sm = &sr_main;
1344 u32 n_left_from, next_index, *from, *to_next;
1346 from = vlib_frame_vector_args (from_frame);
1347 n_left_from = from_frame->n_vectors;
1349 next_index = node->cached_next_index;
1351 int encap_pkts = 0, bsid_pkts = 0;
1353 while (n_left_from > 0)
1357 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1360 while (n_left_from >= 8 && n_left_to_next >= 4)
1362 u32 bi0, bi1, bi2, bi3;
1363 vlib_buffer_t *b0, *b1, *b2, *b3;
1364 u32 next0, next1, next2, next3;
1365 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1366 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1367 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1368 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1370 /* Prefetch next iteration. */
1372 vlib_buffer_t *p4, *p5, *p6, *p7;
1374 p4 = vlib_get_buffer (vm, from[4]);
1375 p5 = vlib_get_buffer (vm, from[5]);
1376 p6 = vlib_get_buffer (vm, from[6]);
1377 p7 = vlib_get_buffer (vm, from[7]);
1379 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1380 vlib_prefetch_buffer_header (p4, LOAD);
1381 vlib_prefetch_buffer_header (p5, LOAD);
1382 vlib_prefetch_buffer_header (p6, LOAD);
1383 vlib_prefetch_buffer_header (p7, LOAD);
1385 clib_prefetch_store (p4->data);
1386 clib_prefetch_store (p5->data);
1387 clib_prefetch_store (p6->data);
1388 clib_prefetch_store (p7->data);
1391 to_next[0] = bi0 = from[0];
1392 to_next[1] = bi1 = from[1];
1393 to_next[2] = bi2 = from[2];
1394 to_next[3] = bi3 = from[3];
1398 n_left_to_next -= 4;
1400 b0 = vlib_get_buffer (vm, bi0);
1401 b1 = vlib_get_buffer (vm, bi1);
1402 b2 = vlib_get_buffer (vm, bi2);
1403 b3 = vlib_get_buffer (vm, bi3);
1406 pool_elt_at_index (sm->sid_lists,
1407 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1409 pool_elt_at_index (sm->sid_lists,
1410 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1412 pool_elt_at_index (sm->sid_lists,
1413 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1415 pool_elt_at_index (sm->sid_lists,
1416 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1418 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1419 vec_len (sl0->rewrite));
1420 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1421 vec_len (sl1->rewrite));
1422 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1423 vec_len (sl2->rewrite));
1424 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1425 vec_len (sl3->rewrite));
1427 ip0_encap = vlib_buffer_get_current (b0);
1428 ip1_encap = vlib_buffer_get_current (b1);
1429 ip2_encap = vlib_buffer_get_current (b2);
1430 ip3_encap = vlib_buffer_get_current (b3);
1432 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1433 sl0->rewrite, vec_len (sl0->rewrite));
1434 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1435 sl1->rewrite, vec_len (sl1->rewrite));
1436 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1437 sl2->rewrite, vec_len (sl2->rewrite));
1438 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1439 sl3->rewrite, vec_len (sl3->rewrite));
1441 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1442 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1443 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1444 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1446 ip0 = vlib_buffer_get_current (b0);
1447 ip1 = vlib_buffer_get_current (b1);
1448 ip2 = vlib_buffer_get_current (b2);
1449 ip3 = vlib_buffer_get_current (b3);
1451 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1452 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1453 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1454 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
1456 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1457 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1458 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1459 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1461 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1463 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1465 sr_policy_rewrite_trace_t *tr =
1466 vlib_add_trace (vm, node, b0, sizeof (*tr));
1467 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1468 sizeof (tr->src.as_u8));
1469 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1470 sizeof (tr->dst.as_u8));
1473 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1475 sr_policy_rewrite_trace_t *tr =
1476 vlib_add_trace (vm, node, b1, sizeof (*tr));
1477 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1478 sizeof (tr->src.as_u8));
1479 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1480 sizeof (tr->dst.as_u8));
1483 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1485 sr_policy_rewrite_trace_t *tr =
1486 vlib_add_trace (vm, node, b2, sizeof (*tr));
1487 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1488 sizeof (tr->src.as_u8));
1489 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1490 sizeof (tr->dst.as_u8));
1493 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1495 sr_policy_rewrite_trace_t *tr =
1496 vlib_add_trace (vm, node, b3, sizeof (*tr));
1497 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1498 sizeof (tr->src.as_u8));
1499 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1500 sizeof (tr->dst.as_u8));
1505 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1506 n_left_to_next, bi0, bi1, bi2, bi3,
1507 next0, next1, next2, next3);
1510 /* Single loop for potentially the last three packets */
1511 while (n_left_from > 0 && n_left_to_next > 0)
1515 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1517 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1524 n_left_to_next -= 1;
1525 b0 = vlib_get_buffer (vm, bi0);
1528 pool_elt_at_index (sm->sid_lists,
1529 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1530 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1531 vec_len (sl0->rewrite));
1533 ip0_encap = vlib_buffer_get_current (b0);
1535 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1536 sl0->rewrite, vec_len (sl0->rewrite));
1537 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1539 ip0 = vlib_buffer_get_current (b0);
1541 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1543 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1545 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1546 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1548 sr_policy_rewrite_trace_t *tr =
1549 vlib_add_trace (vm, node, b0, sizeof (*tr));
1550 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1551 sizeof (tr->src.as_u8));
1552 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1553 sizeof (tr->dst.as_u8));
1557 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1558 n_left_to_next, bi0, next0);
1561 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1564 /* Update counters */
1565 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1566 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1568 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1569 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1572 return from_frame->n_vectors;
1576 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1577 .function = sr_policy_rewrite_encaps,
1578 .name = "sr-pl-rewrite-encaps",
1579 .vector_size = sizeof (u32),
1580 .format_trace = format_sr_policy_rewrite_trace,
1581 .type = VLIB_NODE_TYPE_INTERNAL,
1582 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1583 .error_strings = sr_policy_rewrite_error_strings,
1584 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1586 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1587 foreach_sr_policy_rewrite_next
1594 * @brief IPv4 encapsulation processing as per RFC2473
1596 static_always_inline void
1597 encaps_processing_v4 (vlib_node_runtime_t * node,
1599 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1602 ip6_sr_header_t *sr0;
1607 /* Inner IPv4: Decrement TTL & update checksum */
1608 ip0_encap->ttl -= 1;
1609 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1610 checksum0 += checksum0 >= 0xffff;
1611 ip0_encap->checksum = checksum0;
1613 /* Outer IPv6: Update length, FL, proto */
1614 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1615 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1616 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1617 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1618 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1619 (flow_label & 0x0000ffff));
1620 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1622 sr0 = (void *) (ip0 + 1);
1623 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1626 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1630 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1633 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1634 vlib_frame_t * from_frame)
1636 ip6_sr_main_t *sm = &sr_main;
1637 u32 n_left_from, next_index, *from, *to_next;
1639 from = vlib_frame_vector_args (from_frame);
1640 n_left_from = from_frame->n_vectors;
1642 next_index = node->cached_next_index;
1644 int encap_pkts = 0, bsid_pkts = 0;
1646 while (n_left_from > 0)
1650 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1653 while (n_left_from >= 8 && n_left_to_next >= 4)
1655 u32 bi0, bi1, bi2, bi3;
1656 vlib_buffer_t *b0, *b1, *b2, *b3;
1657 u32 next0, next1, next2, next3;
1658 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1659 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1660 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1661 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1663 /* Prefetch next iteration. */
1665 vlib_buffer_t *p4, *p5, *p6, *p7;
1667 p4 = vlib_get_buffer (vm, from[4]);
1668 p5 = vlib_get_buffer (vm, from[5]);
1669 p6 = vlib_get_buffer (vm, from[6]);
1670 p7 = vlib_get_buffer (vm, from[7]);
1672 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1673 vlib_prefetch_buffer_header (p4, LOAD);
1674 vlib_prefetch_buffer_header (p5, LOAD);
1675 vlib_prefetch_buffer_header (p6, LOAD);
1676 vlib_prefetch_buffer_header (p7, LOAD);
1678 clib_prefetch_store (p4->data);
1679 clib_prefetch_store (p5->data);
1680 clib_prefetch_store (p6->data);
1681 clib_prefetch_store (p7->data);
1684 to_next[0] = bi0 = from[0];
1685 to_next[1] = bi1 = from[1];
1686 to_next[2] = bi2 = from[2];
1687 to_next[3] = bi3 = from[3];
1691 n_left_to_next -= 4;
1693 b0 = vlib_get_buffer (vm, bi0);
1694 b1 = vlib_get_buffer (vm, bi1);
1695 b2 = vlib_get_buffer (vm, bi2);
1696 b3 = vlib_get_buffer (vm, bi3);
1699 pool_elt_at_index (sm->sid_lists,
1700 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1702 pool_elt_at_index (sm->sid_lists,
1703 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1705 pool_elt_at_index (sm->sid_lists,
1706 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1708 pool_elt_at_index (sm->sid_lists,
1709 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1710 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1711 vec_len (sl0->rewrite));
1712 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1713 vec_len (sl1->rewrite));
1714 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1715 vec_len (sl2->rewrite));
1716 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1717 vec_len (sl3->rewrite));
1719 ip0_encap = vlib_buffer_get_current (b0);
1720 ip1_encap = vlib_buffer_get_current (b1);
1721 ip2_encap = vlib_buffer_get_current (b2);
1722 ip3_encap = vlib_buffer_get_current (b3);
1724 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1725 sl0->rewrite, vec_len (sl0->rewrite));
1726 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1727 sl1->rewrite, vec_len (sl1->rewrite));
1728 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1729 sl2->rewrite, vec_len (sl2->rewrite));
1730 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1731 sl3->rewrite, vec_len (sl3->rewrite));
1733 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1734 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1735 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1736 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1738 ip0 = vlib_buffer_get_current (b0);
1739 ip1 = vlib_buffer_get_current (b1);
1740 ip2 = vlib_buffer_get_current (b2);
1741 ip3 = vlib_buffer_get_current (b3);
1743 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1744 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1745 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1746 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1748 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1749 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1750 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1751 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1753 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1755 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1757 sr_policy_rewrite_trace_t *tr =
1758 vlib_add_trace (vm, node, b0, sizeof (*tr));
1759 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1760 sizeof (tr->src.as_u8));
1761 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1762 sizeof (tr->dst.as_u8));
1765 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1767 sr_policy_rewrite_trace_t *tr =
1768 vlib_add_trace (vm, node, b1, sizeof (*tr));
1769 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1770 sizeof (tr->src.as_u8));
1771 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1772 sizeof (tr->dst.as_u8));
1775 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1777 sr_policy_rewrite_trace_t *tr =
1778 vlib_add_trace (vm, node, b2, sizeof (*tr));
1779 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1780 sizeof (tr->src.as_u8));
1781 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1782 sizeof (tr->dst.as_u8));
1785 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1787 sr_policy_rewrite_trace_t *tr =
1788 vlib_add_trace (vm, node, b3, sizeof (*tr));
1789 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1790 sizeof (tr->src.as_u8));
1791 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1792 sizeof (tr->dst.as_u8));
1797 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1798 n_left_to_next, bi0, bi1, bi2, bi3,
1799 next0, next1, next2, next3);
1802 /* Single loop for potentially the last three packets */
1803 while (n_left_from > 0 && n_left_to_next > 0)
1807 ip6_header_t *ip0 = 0;
1808 ip4_header_t *ip0_encap = 0;
1810 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1817 n_left_to_next -= 1;
1818 b0 = vlib_get_buffer (vm, bi0);
1821 pool_elt_at_index (sm->sid_lists,
1822 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1823 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1824 vec_len (sl0->rewrite));
1826 ip0_encap = vlib_buffer_get_current (b0);
1828 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1829 sl0->rewrite, vec_len (sl0->rewrite));
1830 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1832 ip0 = vlib_buffer_get_current (b0);
1834 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1836 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1838 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1839 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1841 sr_policy_rewrite_trace_t *tr =
1842 vlib_add_trace (vm, node, b0, sizeof (*tr));
1843 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1844 sizeof (tr->src.as_u8));
1845 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1846 sizeof (tr->dst.as_u8));
1850 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1851 n_left_to_next, bi0, next0);
1854 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1857 /* Update counters */
1858 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1859 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1861 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1862 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1865 return from_frame->n_vectors;
1869 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1870 .function = sr_policy_rewrite_encaps_v4,
1871 .name = "sr-pl-rewrite-encaps-v4",
1872 .vector_size = sizeof (u32),
1873 .format_trace = format_sr_policy_rewrite_trace,
1874 .type = VLIB_NODE_TYPE_INTERNAL,
1875 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1876 .error_strings = sr_policy_rewrite_error_strings,
1877 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1879 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1880 foreach_sr_policy_rewrite_next
1887 ip_flow_hash (void *data)
1889 ip4_header_t *iph = (ip4_header_t *) data;
1891 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1892 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1894 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1900 return (*((u64 *) m) & 0xffffffffffff);
1904 l2_flow_hash (vlib_buffer_t * b0)
1906 ethernet_header_t *eh;
1908 uword is_ip, eh_size;
1911 eh = vlib_buffer_get_current (b0);
1912 eh_type = clib_net_to_host_u16 (eh->type);
1913 eh_size = ethernet_buffer_header_size (b0);
1915 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1917 /* since we have 2 cache lines, use them */
1919 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1923 b = mac_to_u64 ((u8 *) eh->dst_address);
1924 c = mac_to_u64 ((u8 *) eh->src_address);
1925 hash_mix64 (a, b, c);
1931 * @brief Graph node for applying a SR policy into a L2 frame
1934 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1935 vlib_frame_t * from_frame)
1937 ip6_sr_main_t *sm = &sr_main;
1938 u32 n_left_from, next_index, *from, *to_next;
1940 from = vlib_frame_vector_args (from_frame);
1941 n_left_from = from_frame->n_vectors;
1943 next_index = node->cached_next_index;
1945 int encap_pkts = 0, bsid_pkts = 0;
1947 while (n_left_from > 0)
1951 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1954 while (n_left_from >= 8 && n_left_to_next >= 4)
1956 u32 bi0, bi1, bi2, bi3;
1957 vlib_buffer_t *b0, *b1, *b2, *b3;
1958 u32 next0, next1, next2, next3;
1959 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1960 ethernet_header_t *en0, *en1, *en2, *en3;
1961 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1962 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1963 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1964 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1965 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1967 /* Prefetch next iteration. */
1969 vlib_buffer_t *p4, *p5, *p6, *p7;
1971 p4 = vlib_get_buffer (vm, from[4]);
1972 p5 = vlib_get_buffer (vm, from[5]);
1973 p6 = vlib_get_buffer (vm, from[6]);
1974 p7 = vlib_get_buffer (vm, from[7]);
1976 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1977 vlib_prefetch_buffer_header (p4, LOAD);
1978 vlib_prefetch_buffer_header (p5, LOAD);
1979 vlib_prefetch_buffer_header (p6, LOAD);
1980 vlib_prefetch_buffer_header (p7, LOAD);
1982 clib_prefetch_store (p4->data);
1983 clib_prefetch_store (p5->data);
1984 clib_prefetch_store (p6->data);
1985 clib_prefetch_store (p7->data);
1988 to_next[0] = bi0 = from[0];
1989 to_next[1] = bi1 = from[1];
1990 to_next[2] = bi2 = from[2];
1991 to_next[3] = bi3 = from[3];
1995 n_left_to_next -= 4;
1997 b0 = vlib_get_buffer (vm, bi0);
1998 b1 = vlib_get_buffer (vm, bi1);
1999 b2 = vlib_get_buffer (vm, bi2);
2000 b3 = vlib_get_buffer (vm, bi3);
2002 sp0 = pool_elt_at_index (sm->sr_policies,
2003 sm->sw_iface_sr_policies[vnet_buffer
2007 sp1 = pool_elt_at_index (sm->sr_policies,
2008 sm->sw_iface_sr_policies[vnet_buffer
2012 sp2 = pool_elt_at_index (sm->sr_policies,
2013 sm->sw_iface_sr_policies[vnet_buffer
2017 sp3 = pool_elt_at_index (sm->sr_policies,
2018 sm->sw_iface_sr_policies[vnet_buffer
2021 flow_label0 = l2_flow_hash (b0);
2022 flow_label1 = l2_flow_hash (b1);
2023 flow_label2 = l2_flow_hash (b2);
2024 flow_label3 = l2_flow_hash (b3);
2026 if (vec_len (sp0->segments_lists) == 1)
2027 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2030 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2031 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2032 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2033 (vec_len (sp0->segments_lists) - 1))];
2036 if (vec_len (sp1->segments_lists) == 1)
2037 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
2040 vnet_buffer (b1)->ip.flow_hash = flow_label1;
2041 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
2042 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
2043 (vec_len (sp1->segments_lists) - 1))];
2046 if (vec_len (sp2->segments_lists) == 1)
2047 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
2050 vnet_buffer (b2)->ip.flow_hash = flow_label2;
2051 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
2052 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
2053 (vec_len (sp2->segments_lists) - 1))];
2056 if (vec_len (sp3->segments_lists) == 1)
2057 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
2060 vnet_buffer (b3)->ip.flow_hash = flow_label3;
2061 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
2062 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
2063 (vec_len (sp3->segments_lists) - 1))];
2067 pool_elt_at_index (sm->sid_lists,
2068 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2070 pool_elt_at_index (sm->sid_lists,
2071 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2073 pool_elt_at_index (sm->sid_lists,
2074 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2076 pool_elt_at_index (sm->sid_lists,
2077 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2079 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2080 vec_len (sl0->rewrite));
2081 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2082 vec_len (sl1->rewrite));
2083 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2084 vec_len (sl2->rewrite));
2085 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2086 vec_len (sl3->rewrite));
2088 en0 = vlib_buffer_get_current (b0);
2089 en1 = vlib_buffer_get_current (b1);
2090 en2 = vlib_buffer_get_current (b2);
2091 en3 = vlib_buffer_get_current (b3);
2093 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2094 sl0->rewrite, vec_len (sl0->rewrite));
2095 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2096 sl1->rewrite, vec_len (sl1->rewrite));
2097 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2098 sl2->rewrite, vec_len (sl2->rewrite));
2099 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2100 sl3->rewrite, vec_len (sl3->rewrite));
2102 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2103 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2104 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2105 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2107 ip0 = vlib_buffer_get_current (b0);
2108 ip1 = vlib_buffer_get_current (b1);
2109 ip2 = vlib_buffer_get_current (b2);
2110 ip3 = vlib_buffer_get_current (b3);
2112 ip0->payload_length =
2113 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2114 ip1->payload_length =
2115 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2116 ip2->payload_length =
2117 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2118 ip3->payload_length =
2119 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2121 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2123 sr0 = (void *) (ip0 + 1);
2124 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2127 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2129 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2131 sr1 = (void *) (ip1 + 1);
2132 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2135 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2137 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2139 sr2 = (void *) (ip2 + 1);
2140 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2143 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2145 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2147 sr3 = (void *) (ip3 + 1);
2148 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2151 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2153 /* TC is set to 0 for all ethernet frames, should be taken from COS
2154 * od DSCP of encapsulated packet in the future */
2155 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2156 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2157 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2158 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2159 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2160 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2161 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2162 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2164 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2166 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2168 sr_policy_rewrite_trace_t *tr =
2169 vlib_add_trace (vm, node, b0, sizeof (*tr));
2170 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2171 sizeof (tr->src.as_u8));
2172 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2173 sizeof (tr->dst.as_u8));
2176 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2178 sr_policy_rewrite_trace_t *tr =
2179 vlib_add_trace (vm, node, b1, sizeof (*tr));
2180 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2181 sizeof (tr->src.as_u8));
2182 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2183 sizeof (tr->dst.as_u8));
2186 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2188 sr_policy_rewrite_trace_t *tr =
2189 vlib_add_trace (vm, node, b2, sizeof (*tr));
2190 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2191 sizeof (tr->src.as_u8));
2192 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2193 sizeof (tr->dst.as_u8));
2196 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2198 sr_policy_rewrite_trace_t *tr =
2199 vlib_add_trace (vm, node, b3, sizeof (*tr));
2200 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2201 sizeof (tr->src.as_u8));
2202 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2203 sizeof (tr->dst.as_u8));
2208 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2209 n_left_to_next, bi0, bi1, bi2, bi3,
2210 next0, next1, next2, next3);
2213 /* Single loop for potentially the last three packets */
2214 while (n_left_from > 0 && n_left_to_next > 0)
2218 ip6_header_t *ip0 = 0;
2219 ip6_sr_header_t *sr0;
2220 ethernet_header_t *en0;
2221 ip6_sr_policy_t *sp0;
2223 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2231 n_left_to_next -= 1;
2232 b0 = vlib_get_buffer (vm, bi0);
2234 /* Find the SR policy */
2235 sp0 = pool_elt_at_index (sm->sr_policies,
2236 sm->sw_iface_sr_policies[vnet_buffer
2239 flow_label0 = l2_flow_hash (b0);
2241 /* In case there is more than one SL, LB among them */
2242 if (vec_len (sp0->segments_lists) == 1)
2243 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2246 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2247 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2248 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2249 (vec_len (sp0->segments_lists) - 1))];
2252 pool_elt_at_index (sm->sid_lists,
2253 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2254 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2255 vec_len (sl0->rewrite));
2257 en0 = vlib_buffer_get_current (b0);
2259 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2260 sl0->rewrite, vec_len (sl0->rewrite));
2262 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2264 ip0 = vlib_buffer_get_current (b0);
2266 ip0->payload_length =
2267 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2269 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2271 sr0 = (void *) (ip0 + 1);
2272 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2275 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2277 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2278 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2280 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2281 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2283 sr_policy_rewrite_trace_t *tr =
2284 vlib_add_trace (vm, node, b0, sizeof (*tr));
2285 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2286 sizeof (tr->src.as_u8));
2287 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2288 sizeof (tr->dst.as_u8));
2292 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2293 n_left_to_next, bi0, next0);
2296 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2299 /* Update counters */
2300 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2301 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2303 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2304 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2307 return from_frame->n_vectors;
2311 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2312 .function = sr_policy_rewrite_encaps_l2,
2313 .name = "sr-pl-rewrite-encaps-l2",
2314 .vector_size = sizeof (u32),
2315 .format_trace = format_sr_policy_rewrite_trace,
2316 .type = VLIB_NODE_TYPE_INTERNAL,
2317 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2318 .error_strings = sr_policy_rewrite_error_strings,
2319 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2321 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2322 foreach_sr_policy_rewrite_next
2329 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2332 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2333 vlib_frame_t * from_frame)
2335 ip6_sr_main_t *sm = &sr_main;
2336 u32 n_left_from, next_index, *from, *to_next;
2338 from = vlib_frame_vector_args (from_frame);
2339 n_left_from = from_frame->n_vectors;
2341 next_index = node->cached_next_index;
2343 int insert_pkts = 0, bsid_pkts = 0;
2345 while (n_left_from > 0)
2349 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2352 while (n_left_from >= 8 && n_left_to_next >= 4)
2354 u32 bi0, bi1, bi2, bi3;
2355 vlib_buffer_t *b0, *b1, *b2, *b3;
2356 u32 next0, next1, next2, next3;
2357 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2358 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2359 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2360 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2361 u16 new_l0, new_l1, new_l2, new_l3;
2363 /* Prefetch next iteration. */
2365 vlib_buffer_t *p4, *p5, *p6, *p7;
2367 p4 = vlib_get_buffer (vm, from[4]);
2368 p5 = vlib_get_buffer (vm, from[5]);
2369 p6 = vlib_get_buffer (vm, from[6]);
2370 p7 = vlib_get_buffer (vm, from[7]);
2372 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2373 vlib_prefetch_buffer_header (p4, LOAD);
2374 vlib_prefetch_buffer_header (p5, LOAD);
2375 vlib_prefetch_buffer_header (p6, LOAD);
2376 vlib_prefetch_buffer_header (p7, LOAD);
2378 clib_prefetch_store (p4->data);
2379 clib_prefetch_store (p5->data);
2380 clib_prefetch_store (p6->data);
2381 clib_prefetch_store (p7->data);
2384 to_next[0] = bi0 = from[0];
2385 to_next[1] = bi1 = from[1];
2386 to_next[2] = bi2 = from[2];
2387 to_next[3] = bi3 = from[3];
2391 n_left_to_next -= 4;
2393 b0 = vlib_get_buffer (vm, bi0);
2394 b1 = vlib_get_buffer (vm, bi1);
2395 b2 = vlib_get_buffer (vm, bi2);
2396 b3 = vlib_get_buffer (vm, bi3);
2399 pool_elt_at_index (sm->sid_lists,
2400 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2402 pool_elt_at_index (sm->sid_lists,
2403 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2405 pool_elt_at_index (sm->sid_lists,
2406 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2408 pool_elt_at_index (sm->sid_lists,
2409 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2410 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2411 vec_len (sl0->rewrite));
2412 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2413 vec_len (sl1->rewrite));
2414 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2415 vec_len (sl2->rewrite));
2416 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2417 vec_len (sl3->rewrite));
2419 ip0 = vlib_buffer_get_current (b0);
2420 ip1 = vlib_buffer_get_current (b1);
2421 ip2 = vlib_buffer_get_current (b2);
2422 ip3 = vlib_buffer_get_current (b3);
2424 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2426 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2427 ip6_ext_header_len (ip0 + 1));
2429 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2431 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2433 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2434 ip6_ext_header_len (ip1 + 1));
2436 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2438 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2440 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2441 ip6_ext_header_len (ip2 + 1));
2443 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2445 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2447 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2448 ip6_ext_header_len (ip3 + 1));
2450 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2452 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2453 (void *) sr0 - (void *) ip0);
2454 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2455 (void *) sr1 - (void *) ip1);
2456 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2457 (void *) sr2 - (void *) ip2);
2458 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2459 (void *) sr3 - (void *) ip3);
2461 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2462 sl0->rewrite, vec_len (sl0->rewrite));
2463 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2464 sl1->rewrite, vec_len (sl1->rewrite));
2465 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2466 sl2->rewrite, vec_len (sl2->rewrite));
2467 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2468 sl3->rewrite, vec_len (sl3->rewrite));
2470 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2471 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2472 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2473 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2475 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2476 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2477 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2478 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2480 ip0->hop_limit -= 1;
2481 ip1->hop_limit -= 1;
2482 ip2->hop_limit -= 1;
2483 ip3->hop_limit -= 1;
2486 clib_net_to_host_u16 (ip0->payload_length) +
2487 vec_len (sl0->rewrite);
2489 clib_net_to_host_u16 (ip1->payload_length) +
2490 vec_len (sl1->rewrite);
2492 clib_net_to_host_u16 (ip2->payload_length) +
2493 vec_len (sl2->rewrite);
2495 clib_net_to_host_u16 (ip3->payload_length) +
2496 vec_len (sl3->rewrite);
2498 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2499 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2500 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2501 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2503 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2504 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2505 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2506 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2508 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2509 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2510 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2511 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2512 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2513 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2514 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2515 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2517 ip0->dst_address.as_u64[0] =
2518 (sr0->segments + sr0->segments_left)->as_u64[0];
2519 ip0->dst_address.as_u64[1] =
2520 (sr0->segments + sr0->segments_left)->as_u64[1];
2521 ip1->dst_address.as_u64[0] =
2522 (sr1->segments + sr1->segments_left)->as_u64[0];
2523 ip1->dst_address.as_u64[1] =
2524 (sr1->segments + sr1->segments_left)->as_u64[1];
2525 ip2->dst_address.as_u64[0] =
2526 (sr2->segments + sr2->segments_left)->as_u64[0];
2527 ip2->dst_address.as_u64[1] =
2528 (sr2->segments + sr2->segments_left)->as_u64[1];
2529 ip3->dst_address.as_u64[0] =
2530 (sr3->segments + sr3->segments_left)->as_u64[0];
2531 ip3->dst_address.as_u64[1] =
2532 (sr3->segments + sr3->segments_left)->as_u64[1];
2534 ip6_ext_header_t *ip_ext;
2535 if (ip0 + 1 == (void *) sr0)
2537 sr0->protocol = ip0->protocol;
2538 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2542 ip_ext = (void *) (ip0 + 1);
2543 sr0->protocol = ip_ext->next_hdr;
2544 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2547 if (ip1 + 1 == (void *) sr1)
2549 sr1->protocol = ip1->protocol;
2550 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2554 ip_ext = (void *) (ip2 + 1);
2555 sr2->protocol = ip_ext->next_hdr;
2556 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2559 if (ip2 + 1 == (void *) sr2)
2561 sr2->protocol = ip2->protocol;
2562 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2566 ip_ext = (void *) (ip2 + 1);
2567 sr2->protocol = ip_ext->next_hdr;
2568 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2571 if (ip3 + 1 == (void *) sr3)
2573 sr3->protocol = ip3->protocol;
2574 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2578 ip_ext = (void *) (ip3 + 1);
2579 sr3->protocol = ip_ext->next_hdr;
2580 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2585 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2587 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2589 sr_policy_rewrite_trace_t *tr =
2590 vlib_add_trace (vm, node, b0, sizeof (*tr));
2591 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2592 sizeof (tr->src.as_u8));
2593 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2594 sizeof (tr->dst.as_u8));
2597 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2599 sr_policy_rewrite_trace_t *tr =
2600 vlib_add_trace (vm, node, b1, sizeof (*tr));
2601 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2602 sizeof (tr->src.as_u8));
2603 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2604 sizeof (tr->dst.as_u8));
2607 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2609 sr_policy_rewrite_trace_t *tr =
2610 vlib_add_trace (vm, node, b2, sizeof (*tr));
2611 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2612 sizeof (tr->src.as_u8));
2613 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2614 sizeof (tr->dst.as_u8));
2617 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2619 sr_policy_rewrite_trace_t *tr =
2620 vlib_add_trace (vm, node, b3, sizeof (*tr));
2621 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2622 sizeof (tr->src.as_u8));
2623 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2624 sizeof (tr->dst.as_u8));
2628 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2629 n_left_to_next, bi0, bi1, bi2, bi3,
2630 next0, next1, next2, next3);
2633 /* Single loop for potentially the last three packets */
2634 while (n_left_from > 0 && n_left_to_next > 0)
2638 ip6_header_t *ip0 = 0;
2639 ip6_sr_header_t *sr0 = 0;
2641 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2649 n_left_to_next -= 1;
2651 b0 = vlib_get_buffer (vm, bi0);
2653 pool_elt_at_index (sm->sid_lists,
2654 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2655 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2656 vec_len (sl0->rewrite));
2658 ip0 = vlib_buffer_get_current (b0);
2660 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2662 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2663 ip6_ext_header_len (ip0 + 1));
2665 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2667 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2668 (void *) sr0 - (void *) ip0);
2669 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2670 sl0->rewrite, vec_len (sl0->rewrite));
2672 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2674 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2675 ip0->hop_limit -= 1;
2677 clib_net_to_host_u16 (ip0->payload_length) +
2678 vec_len (sl0->rewrite);
2679 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2681 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2682 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2683 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2685 ip0->dst_address.as_u64[0] =
2686 (sr0->segments + sr0->segments_left)->as_u64[0];
2687 ip0->dst_address.as_u64[1] =
2688 (sr0->segments + sr0->segments_left)->as_u64[1];
2690 if (ip0 + 1 == (void *) sr0)
2692 sr0->protocol = ip0->protocol;
2693 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2697 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2698 sr0->protocol = ip_ext->next_hdr;
2699 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2702 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2703 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2705 sr_policy_rewrite_trace_t *tr =
2706 vlib_add_trace (vm, node, b0, sizeof (*tr));
2707 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2708 sizeof (tr->src.as_u8));
2709 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2710 sizeof (tr->dst.as_u8));
2715 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2716 n_left_to_next, bi0, next0);
2719 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2722 /* Update counters */
2723 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2724 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2726 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2727 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2729 return from_frame->n_vectors;
2733 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2734 .function = sr_policy_rewrite_insert,
2735 .name = "sr-pl-rewrite-insert",
2736 .vector_size = sizeof (u32),
2737 .format_trace = format_sr_policy_rewrite_trace,
2738 .type = VLIB_NODE_TYPE_INTERNAL,
2739 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2740 .error_strings = sr_policy_rewrite_error_strings,
2741 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2743 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2744 foreach_sr_policy_rewrite_next
2751 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2754 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2755 vlib_frame_t * from_frame)
2757 ip6_sr_main_t *sm = &sr_main;
2758 u32 n_left_from, next_index, *from, *to_next;
2760 from = vlib_frame_vector_args (from_frame);
2761 n_left_from = from_frame->n_vectors;
2763 next_index = node->cached_next_index;
2765 int insert_pkts = 0, bsid_pkts = 0;
2767 while (n_left_from > 0)
2771 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2774 while (n_left_from >= 8 && n_left_to_next >= 4)
2776 u32 bi0, bi1, bi2, bi3;
2777 vlib_buffer_t *b0, *b1, *b2, *b3;
2778 u32 next0, next1, next2, next3;
2779 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2780 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2781 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2782 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2783 u16 new_l0, new_l1, new_l2, new_l3;
2785 /* Prefetch next iteration. */
2787 vlib_buffer_t *p4, *p5, *p6, *p7;
2789 p4 = vlib_get_buffer (vm, from[4]);
2790 p5 = vlib_get_buffer (vm, from[5]);
2791 p6 = vlib_get_buffer (vm, from[6]);
2792 p7 = vlib_get_buffer (vm, from[7]);
2794 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2795 vlib_prefetch_buffer_header (p4, LOAD);
2796 vlib_prefetch_buffer_header (p5, LOAD);
2797 vlib_prefetch_buffer_header (p6, LOAD);
2798 vlib_prefetch_buffer_header (p7, LOAD);
2800 clib_prefetch_store (p4->data);
2801 clib_prefetch_store (p5->data);
2802 clib_prefetch_store (p6->data);
2803 clib_prefetch_store (p7->data);
2806 to_next[0] = bi0 = from[0];
2807 to_next[1] = bi1 = from[1];
2808 to_next[2] = bi2 = from[2];
2809 to_next[3] = bi3 = from[3];
2813 n_left_to_next -= 4;
2815 b0 = vlib_get_buffer (vm, bi0);
2816 b1 = vlib_get_buffer (vm, bi1);
2817 b2 = vlib_get_buffer (vm, bi2);
2818 b3 = vlib_get_buffer (vm, bi3);
2821 pool_elt_at_index (sm->sid_lists,
2822 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2824 pool_elt_at_index (sm->sid_lists,
2825 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2827 pool_elt_at_index (sm->sid_lists,
2828 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2830 pool_elt_at_index (sm->sid_lists,
2831 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2832 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2833 vec_len (sl0->rewrite_bsid));
2834 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2835 vec_len (sl1->rewrite_bsid));
2836 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2837 vec_len (sl2->rewrite_bsid));
2838 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2839 vec_len (sl3->rewrite_bsid));
2841 ip0 = vlib_buffer_get_current (b0);
2842 ip1 = vlib_buffer_get_current (b1);
2843 ip2 = vlib_buffer_get_current (b2);
2844 ip3 = vlib_buffer_get_current (b3);
2846 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2848 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2849 ip6_ext_header_len (ip0 + 1));
2851 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2853 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2855 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2856 ip6_ext_header_len (ip1 + 1));
2858 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2860 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2862 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2863 ip6_ext_header_len (ip2 + 1));
2865 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2867 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2869 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2870 ip6_ext_header_len (ip3 + 1));
2872 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2874 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2875 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2876 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2877 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2878 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2879 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2880 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2881 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2883 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2884 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2885 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2886 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2887 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2888 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2889 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2890 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2892 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2893 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2894 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2895 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2897 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2898 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2899 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2900 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2902 ip0->hop_limit -= 1;
2903 ip1->hop_limit -= 1;
2904 ip2->hop_limit -= 1;
2905 ip3->hop_limit -= 1;
2908 clib_net_to_host_u16 (ip0->payload_length) +
2909 vec_len (sl0->rewrite_bsid);
2911 clib_net_to_host_u16 (ip1->payload_length) +
2912 vec_len (sl1->rewrite_bsid);
2914 clib_net_to_host_u16 (ip2->payload_length) +
2915 vec_len (sl2->rewrite_bsid);
2917 clib_net_to_host_u16 (ip3->payload_length) +
2918 vec_len (sl3->rewrite_bsid);
2920 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2921 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2922 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2923 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2925 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2926 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2927 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2928 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2930 ip0->dst_address.as_u64[0] =
2931 (sr0->segments + sr0->segments_left)->as_u64[0];
2932 ip0->dst_address.as_u64[1] =
2933 (sr0->segments + sr0->segments_left)->as_u64[1];
2934 ip1->dst_address.as_u64[0] =
2935 (sr1->segments + sr1->segments_left)->as_u64[0];
2936 ip1->dst_address.as_u64[1] =
2937 (sr1->segments + sr1->segments_left)->as_u64[1];
2938 ip2->dst_address.as_u64[0] =
2939 (sr2->segments + sr2->segments_left)->as_u64[0];
2940 ip2->dst_address.as_u64[1] =
2941 (sr2->segments + sr2->segments_left)->as_u64[1];
2942 ip3->dst_address.as_u64[0] =
2943 (sr3->segments + sr3->segments_left)->as_u64[0];
2944 ip3->dst_address.as_u64[1] =
2945 (sr3->segments + sr3->segments_left)->as_u64[1];
2947 ip6_ext_header_t *ip_ext;
2948 if (ip0 + 1 == (void *) sr0)
2950 sr0->protocol = ip0->protocol;
2951 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2955 ip_ext = (void *) (ip0 + 1);
2956 sr0->protocol = ip_ext->next_hdr;
2957 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2960 if (ip1 + 1 == (void *) sr1)
2962 sr1->protocol = ip1->protocol;
2963 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2967 ip_ext = (void *) (ip2 + 1);
2968 sr2->protocol = ip_ext->next_hdr;
2969 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2972 if (ip2 + 1 == (void *) sr2)
2974 sr2->protocol = ip2->protocol;
2975 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2979 ip_ext = (void *) (ip2 + 1);
2980 sr2->protocol = ip_ext->next_hdr;
2981 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2984 if (ip3 + 1 == (void *) sr3)
2986 sr3->protocol = ip3->protocol;
2987 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2991 ip_ext = (void *) (ip3 + 1);
2992 sr3->protocol = ip_ext->next_hdr;
2993 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2998 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3000 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3002 sr_policy_rewrite_trace_t *tr =
3003 vlib_add_trace (vm, node, b0, sizeof (*tr));
3004 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3005 sizeof (tr->src.as_u8));
3006 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3007 sizeof (tr->dst.as_u8));
3010 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3012 sr_policy_rewrite_trace_t *tr =
3013 vlib_add_trace (vm, node, b1, sizeof (*tr));
3014 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3015 sizeof (tr->src.as_u8));
3016 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3017 sizeof (tr->dst.as_u8));
3020 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3022 sr_policy_rewrite_trace_t *tr =
3023 vlib_add_trace (vm, node, b2, sizeof (*tr));
3024 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3025 sizeof (tr->src.as_u8));
3026 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3027 sizeof (tr->dst.as_u8));
3030 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3032 sr_policy_rewrite_trace_t *tr =
3033 vlib_add_trace (vm, node, b3, sizeof (*tr));
3034 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3035 sizeof (tr->src.as_u8));
3036 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3037 sizeof (tr->dst.as_u8));
3041 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3042 n_left_to_next, bi0, bi1, bi2, bi3,
3043 next0, next1, next2, next3);
3046 /* Single loop for potentially the last three packets */
3047 while (n_left_from > 0 && n_left_to_next > 0)
3051 ip6_header_t *ip0 = 0;
3052 ip6_sr_header_t *sr0 = 0;
3054 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3062 n_left_to_next -= 1;
3064 b0 = vlib_get_buffer (vm, bi0);
3066 pool_elt_at_index (sm->sid_lists,
3067 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3068 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3069 vec_len (sl0->rewrite_bsid));
3071 ip0 = vlib_buffer_get_current (b0);
3073 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3075 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3076 ip6_ext_header_len (ip0 + 1));
3078 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3080 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3081 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3082 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3083 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3085 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3087 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3088 ip0->hop_limit -= 1;
3090 clib_net_to_host_u16 (ip0->payload_length) +
3091 vec_len (sl0->rewrite_bsid);
3092 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3094 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3096 ip0->dst_address.as_u64[0] =
3097 (sr0->segments + sr0->segments_left)->as_u64[0];
3098 ip0->dst_address.as_u64[1] =
3099 (sr0->segments + sr0->segments_left)->as_u64[1];
3101 if (ip0 + 1 == (void *) sr0)
3103 sr0->protocol = ip0->protocol;
3104 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3108 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3109 sr0->protocol = ip_ext->next_hdr;
3110 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3113 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3114 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3116 sr_policy_rewrite_trace_t *tr =
3117 vlib_add_trace (vm, node, b0, sizeof (*tr));
3118 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3119 sizeof (tr->src.as_u8));
3120 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3121 sizeof (tr->dst.as_u8));
3126 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3127 n_left_to_next, bi0, next0);
3130 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3133 /* Update counters */
3134 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3135 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3137 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3138 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3140 return from_frame->n_vectors;
3144 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3145 .function = sr_policy_rewrite_b_insert,
3146 .name = "sr-pl-rewrite-b-insert",
3147 .vector_size = sizeof (u32),
3148 .format_trace = format_sr_policy_rewrite_trace,
3149 .type = VLIB_NODE_TYPE_INTERNAL,
3150 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3151 .error_strings = sr_policy_rewrite_error_strings,
3152 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3154 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3155 foreach_sr_policy_rewrite_next
3162 * @brief Function BSID encapsulation
3164 static_always_inline void
3165 end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3166 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3167 u32 *next0, u8 policy_type)
3169 ip6_address_t *new_dst0;
3171 if (PREDICT_FALSE (!sr0))
3172 goto error_bsid_encaps;
3174 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3176 if (PREDICT_TRUE (sr0->segments_left != 0))
3178 sr0->segments_left -= 1;
3179 new_dst0 = (ip6_address_t *) (sr0->segments);
3180 new_dst0 += sr0->segments_left;
3181 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3182 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3185 else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
3190 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3191 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3195 * @brief Graph node for applying a SR policy BSID - Encapsulation
3198 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3199 vlib_frame_t * from_frame)
3201 ip6_sr_main_t *sm = &sr_main;
3202 u32 n_left_from, next_index, *from, *to_next;
3204 from = vlib_frame_vector_args (from_frame);
3205 n_left_from = from_frame->n_vectors;
3207 next_index = node->cached_next_index;
3209 int encap_pkts = 0, bsid_pkts = 0;
3211 while (n_left_from > 0)
3215 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3218 while (n_left_from >= 8 && n_left_to_next >= 4)
3220 u32 bi0, bi1, bi2, bi3;
3221 vlib_buffer_t *b0, *b1, *b2, *b3;
3222 u32 next0, next1, next2, next3;
3223 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3224 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3225 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3226 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3227 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3229 /* Prefetch next iteration. */
3231 vlib_buffer_t *p4, *p5, *p6, *p7;
3233 p4 = vlib_get_buffer (vm, from[4]);
3234 p5 = vlib_get_buffer (vm, from[5]);
3235 p6 = vlib_get_buffer (vm, from[6]);
3236 p7 = vlib_get_buffer (vm, from[7]);
3238 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3239 vlib_prefetch_buffer_header (p4, LOAD);
3240 vlib_prefetch_buffer_header (p5, LOAD);
3241 vlib_prefetch_buffer_header (p6, LOAD);
3242 vlib_prefetch_buffer_header (p7, LOAD);
3244 clib_prefetch_store (p4->data);
3245 clib_prefetch_store (p5->data);
3246 clib_prefetch_store (p6->data);
3247 clib_prefetch_store (p7->data);
3250 to_next[0] = bi0 = from[0];
3251 to_next[1] = bi1 = from[1];
3252 to_next[2] = bi2 = from[2];
3253 to_next[3] = bi3 = from[3];
3257 n_left_to_next -= 4;
3259 b0 = vlib_get_buffer (vm, bi0);
3260 b1 = vlib_get_buffer (vm, bi1);
3261 b2 = vlib_get_buffer (vm, bi2);
3262 b3 = vlib_get_buffer (vm, bi3);
3265 pool_elt_at_index (sm->sid_lists,
3266 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3268 pool_elt_at_index (sm->sid_lists,
3269 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3271 pool_elt_at_index (sm->sid_lists,
3272 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3274 pool_elt_at_index (sm->sid_lists,
3275 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3276 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3277 vec_len (sl0->rewrite));
3278 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3279 vec_len (sl1->rewrite));
3280 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3281 vec_len (sl2->rewrite));
3282 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3283 vec_len (sl3->rewrite));
3285 ip0_encap = vlib_buffer_get_current (b0);
3286 ip1_encap = vlib_buffer_get_current (b1);
3287 ip2_encap = vlib_buffer_get_current (b2);
3288 ip3_encap = vlib_buffer_get_current (b3);
3291 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3294 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3297 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3300 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3303 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3305 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3307 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3309 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3312 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3313 sl0->rewrite, vec_len (sl0->rewrite));
3314 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3315 sl1->rewrite, vec_len (sl1->rewrite));
3316 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3317 sl2->rewrite, vec_len (sl2->rewrite));
3318 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3319 sl3->rewrite, vec_len (sl3->rewrite));
3321 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3322 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3323 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3324 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3326 ip0 = vlib_buffer_get_current (b0);
3327 ip1 = vlib_buffer_get_current (b1);
3328 ip2 = vlib_buffer_get_current (b2);
3329 ip3 = vlib_buffer_get_current (b3);
3331 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3332 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3333 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3334 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
3336 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3338 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3340 sr_policy_rewrite_trace_t *tr =
3341 vlib_add_trace (vm, node, b0, sizeof (*tr));
3342 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3343 sizeof (tr->src.as_u8));
3344 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3345 sizeof (tr->dst.as_u8));
3348 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3350 sr_policy_rewrite_trace_t *tr =
3351 vlib_add_trace (vm, node, b1, sizeof (*tr));
3352 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3353 sizeof (tr->src.as_u8));
3354 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3355 sizeof (tr->dst.as_u8));
3358 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3360 sr_policy_rewrite_trace_t *tr =
3361 vlib_add_trace (vm, node, b2, sizeof (*tr));
3362 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3363 sizeof (tr->src.as_u8));
3364 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3365 sizeof (tr->dst.as_u8));
3368 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3370 sr_policy_rewrite_trace_t *tr =
3371 vlib_add_trace (vm, node, b3, sizeof (*tr));
3372 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3373 sizeof (tr->src.as_u8));
3374 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3375 sizeof (tr->dst.as_u8));
3380 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3381 n_left_to_next, bi0, bi1, bi2, bi3,
3382 next0, next1, next2, next3);
3385 /* Single loop for potentially the last three packets */
3386 while (n_left_from > 0 && n_left_to_next > 0)
3390 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3391 ip6_sr_header_t *sr0;
3393 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3400 n_left_to_next -= 1;
3401 b0 = vlib_get_buffer (vm, bi0);
3404 pool_elt_at_index (sm->sid_lists,
3405 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3406 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3407 vec_len (sl0->rewrite));
3409 ip0_encap = vlib_buffer_get_current (b0);
3411 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3413 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3416 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3417 sl0->rewrite, vec_len (sl0->rewrite));
3418 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3420 ip0 = vlib_buffer_get_current (b0);
3422 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3424 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3425 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3427 sr_policy_rewrite_trace_t *tr =
3428 vlib_add_trace (vm, node, b0, sizeof (*tr));
3429 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3430 sizeof (tr->src.as_u8));
3431 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3432 sizeof (tr->dst.as_u8));
3436 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3437 n_left_to_next, bi0, next0);
3440 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3443 /* Update counters */
3444 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3445 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3447 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3448 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3451 return from_frame->n_vectors;
3455 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3456 .function = sr_policy_rewrite_b_encaps,
3457 .name = "sr-pl-rewrite-b-encaps",
3458 .vector_size = sizeof (u32),
3459 .format_trace = format_sr_policy_rewrite_trace,
3460 .type = VLIB_NODE_TYPE_INTERNAL,
3461 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3462 .error_strings = sr_policy_rewrite_error_strings,
3463 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3465 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3466 foreach_sr_policy_rewrite_next
3472 /*************************** SR Policy plugins ******************************/
3474 * @brief SR Policy plugin registry
3477 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3478 u8 * keyword_str, u8 * def_str,
3479 u8 * params_str, u8 prefix_length,
3481 format_function_t * ls_format,
3482 unformat_function_t * ls_unformat,
3483 sr_p_plugin_callback_t * creation_fn,
3484 sr_p_plugin_callback_t * removal_fn)
3486 ip6_sr_main_t *sm = &sr_main;
3489 sr_policy_fn_registration_t *plugin;
3491 /* Did this function exist? If so update it */
3492 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3495 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3497 /* Else create a new one and set hash key */
3500 pool_get (sm->policy_plugin_functions, plugin);
3501 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3502 plugin - sm->policy_plugin_functions);
3505 clib_memset (plugin, 0, sizeof (*plugin));
3507 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3508 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3509 plugin->prefix_length = prefix_length;
3510 plugin->ls_format = ls_format;
3511 plugin->ls_unformat = ls_unformat;
3512 plugin->creation = creation_fn;
3513 plugin->removal = removal_fn;
3514 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3515 plugin->function_name = format (0, "%s%c", fn_name, 0);
3516 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3517 plugin->def_str = format (0, "%s%c", def_str, 0);
3518 plugin->params_str = format (0, "%s%c", params_str, 0);
3520 return plugin->sr_policy_function_number;
3524 * @brief CLI function to 'show' all available SR LocalSID behaviors
3526 static clib_error_t *
3527 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3528 unformat_input_t * input,
3529 vlib_cli_command_t * cmd)
3531 ip6_sr_main_t *sm = &sr_main;
3532 sr_policy_fn_registration_t *plugin;
3533 sr_policy_fn_registration_t **plugins_vec = 0;
3536 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3539 pool_foreach (plugin, sm->policy_plugin_functions)
3540 { vec_add1 (plugins_vec, plugin); }
3543 vlib_cli_output (vm, "Plugin behaviors:\n");
3544 for (i = 0; i < vec_len (plugins_vec); i++)
3546 plugin = plugins_vec[i];
3547 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3549 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3555 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3556 .path = "show sr policy behaviors",
3557 .short_help = "show sr policy behaviors",
3558 .function = show_sr_policy_behaviors_command_fn,
3562 /*************************** SR Segment Lists DPOs ****************************/
3564 format_sr_segment_list_dpo (u8 * s, va_list * args)
3566 ip6_sr_main_t *sm = &sr_main;
3567 ip6_address_t *addr;
3570 index_t index = va_arg (*args, index_t);
3571 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3572 s = format (s, "SR: Segment List index:[%d]", index);
3573 s = format (s, "\n\tSegments:");
3575 sl = pool_elt_at_index (sm->sid_lists, index);
3577 s = format (s, "< ");
3578 vec_foreach (addr, sl->segments)
3580 s = format (s, "%U, ", format_ip6_address, addr);
3582 s = format (s, "\b\b > - ");
3583 s = format (s, "Weight: %u", sl->weight);
3588 const static dpo_vft_t sr_policy_rewrite_vft = {
3589 .dv_lock = sr_dpo_lock,
3590 .dv_unlock = sr_dpo_unlock,
3591 .dv_format = format_sr_segment_list_dpo,
3594 const static char *const sr_pr_encaps_ip6_nodes[] = {
3595 "sr-pl-rewrite-encaps",
3599 const static char *const sr_pr_encaps_ip4_nodes[] = {
3600 "sr-pl-rewrite-encaps-v4",
3604 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3605 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3606 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3609 const static char *const sr_pr_insert_ip6_nodes[] = {
3610 "sr-pl-rewrite-insert",
3614 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3615 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3618 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3619 "sr-pl-rewrite-b-insert",
3623 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3624 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3627 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3628 "sr-pl-rewrite-b-encaps",
3632 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3633 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3636 /********************* SR Policy Rewrite initialization ***********************/
3638 * @brief SR Policy Rewrite initialization
3641 sr_policy_rewrite_init (vlib_main_t * vm)
3643 ip6_sr_main_t *sm = &sr_main;
3645 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3646 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3647 sizeof (ip6_address_t));
3649 /* Init SR VPO DPOs type */
3650 sr_pr_encaps_dpo_type =
3651 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3653 sr_pr_insert_dpo_type =
3654 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3656 sr_pr_bsid_encaps_dpo_type =
3657 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3659 sr_pr_bsid_insert_dpo_type =
3660 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3662 /* Register the L2 encaps node used in HW redirect */
3663 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3665 sm->fib_table_ip6 = (u32) ~ 0;
3666 sm->fib_table_ip4 = (u32) ~ 0;
3671 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3675 * fd.io coding-style-patch-verification: ON
3678 * eval: (c-set-style "gnu")