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
196 * @param src_v6addr is a encaps IPv6 source addr
198 * @return precomputed rewrite string for encapsulation
201 compute_rewrite_encaps (ip6_address_t *sl, ip6_address_t *src_v6addr, u8 type)
204 ip6_sr_header_t *srh;
205 ip6_sr_pt_tlv_t *srh_pt_tlv;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += IPv6_DEFAULT_HEADER_LENGTH;
212 if (type == SR_POLICY_TYPE_TEF)
214 header_length += sizeof (ip6_sr_header_t);
215 header_length += vec_len (sl) * sizeof (ip6_address_t);
216 header_length += sizeof (ip6_sr_pt_tlv_t);
218 else if (vec_len (sl) > 1)
220 header_length += sizeof (ip6_sr_header_t);
221 header_length += vec_len (sl) * sizeof (ip6_address_t);
224 vec_validate (rs, header_length - 1);
226 iph = (ip6_header_t *) rs;
227 iph->ip_version_traffic_class_and_flow_label =
228 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
229 iph->src_address.as_u64[0] = src_v6addr->as_u64[0];
230 iph->src_address.as_u64[1] = src_v6addr->as_u64[1];
231 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
232 iph->protocol = IP_PROTOCOL_IPV6;
233 iph->hop_limit = sr_pr_encaps_hop_limit;
235 if (type == SR_POLICY_TYPE_TEF)
237 srh = (ip6_sr_header_t *) (iph + 1);
238 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
239 srh->protocol = IP_PROTOCOL_IPV6;
240 srh->type = ROUTING_HEADER_TYPE_SR;
243 srh->segments_left = vec_len (sl) - 1;
244 srh->last_entry = vec_len (sl) - 1;
246 ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
247 sizeof (ip6_sr_pt_tlv_t)) /
250 addrp = srh->segments + vec_len (sl) - 1;
251 vec_foreach (this_address, sl)
253 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
254 sizeof (ip6_address_t));
257 srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
258 srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
259 srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
261 else if (vec_len (sl) > 1)
263 srh = (ip6_sr_header_t *) (iph + 1);
264 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
265 srh->protocol = IP_PROTOCOL_IPV6;
266 srh->type = ROUTING_HEADER_TYPE_SR;
267 srh->segments_left = vec_len (sl) - 1;
268 srh->last_entry = vec_len (sl) - 1;
269 srh->length = ((sizeof (ip6_sr_header_t) +
270 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
273 addrp = srh->segments + vec_len (sl) - 1;
274 vec_foreach (this_address, sl)
276 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
277 sizeof (ip6_address_t));
281 iph->dst_address.as_u64[0] = sl->as_u64[0];
282 iph->dst_address.as_u64[1] = sl->as_u64[1];
287 * @brief SR rewrite string computation for SRH insertion (inline)
289 * @param sl is a vector of IPv6 addresses composing the Segment List
291 * @return precomputed rewrite string for SRH insertion
294 compute_rewrite_insert (ip6_address_t *sl, u8 type)
296 ip6_sr_header_t *srh;
297 ip6_address_t *addrp, *this_address;
298 u32 header_length = 0;
302 header_length += sizeof (ip6_sr_header_t);
303 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
305 vec_validate (rs, header_length - 1);
307 srh = (ip6_sr_header_t *) rs;
308 srh->type = ROUTING_HEADER_TYPE_SR;
309 srh->segments_left = vec_len (sl);
310 srh->last_entry = vec_len (sl);
311 srh->length = ((sizeof (ip6_sr_header_t) +
312 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
315 addrp = srh->segments + vec_len (sl);
316 vec_foreach (this_address, sl)
318 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
319 sizeof (ip6_address_t));
326 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
328 * @param sl is a vector of IPv6 addresses composing the Segment List
330 * @return precomputed rewrite string for SRH insertion with BSID
333 compute_rewrite_bsid (ip6_address_t * sl)
335 ip6_sr_header_t *srh;
336 ip6_address_t *addrp, *this_address;
337 u32 header_length = 0;
341 header_length += sizeof (ip6_sr_header_t);
342 header_length += vec_len (sl) * sizeof (ip6_address_t);
344 vec_validate (rs, header_length - 1);
346 srh = (ip6_sr_header_t *) rs;
347 srh->type = ROUTING_HEADER_TYPE_SR;
348 srh->segments_left = vec_len (sl) - 1;
349 srh->last_entry = vec_len (sl) - 1;
350 srh->length = ((sizeof (ip6_sr_header_t) +
351 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
354 addrp = srh->segments + vec_len (sl) - 1;
355 vec_foreach (this_address, sl)
357 clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
358 sizeof (ip6_address_t));
364 /*************************** SR LB helper functions **************************/
366 * @brief Creates a Segment List and adds it to an SR policy
368 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
369 * not necessarily unique. Hence there might be two Segment List within the
370 * same SR Policy with exactly the same segments and same weight.
372 * @param sr_policy is the SR policy where the SL will be added
373 * @param sl is a vector of IPv6 addresses composing the Segment List
374 * @param encap_src is a encaps IPv6 source addr. optional.
375 * @param weight is the weight of the SegmentList (for load-balancing purposes)
376 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
378 * @return pointer to the just created segment list
380 static inline ip6_sr_sl_t *
381 create_sl (ip6_sr_policy_t *sr_policy, ip6_address_t *sl,
382 ip6_address_t *encap_src, u32 weight, u8 is_encap)
384 ip6_sr_main_t *sm = &sr_main;
385 ip6_sr_sl_t *segment_list;
386 sr_policy_fn_registration_t *plugin = 0;
387 ip6_address_t encap_srcv6 = sr_pr_encaps_src;
389 pool_get (sm->sid_lists, segment_list);
390 clib_memset (segment_list, 0, sizeof (*segment_list));
392 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
394 /* Fill in segment list */
395 segment_list->weight =
396 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
398 segment_list->segments = vec_dup (sl);
399 segment_list->policy_type = sr_policy->type;
401 segment_list->egress_fib_table =
402 ip6_fib_index_from_table_id (sr_policy->fib_table);
408 clib_memcpy_fast (&encap_srcv6, encap_src, sizeof (ip6_address_t));
410 segment_list->rewrite =
411 compute_rewrite_encaps (sl, &encap_srcv6, sr_policy->type);
412 segment_list->rewrite_bsid = segment_list->rewrite;
413 sr_policy->encap_src = encap_srcv6;
417 segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
418 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
421 if (sr_policy->plugin)
424 pool_elt_at_index (sm->policy_plugin_functions,
425 sr_policy->plugin - SR_BEHAVIOR_LAST);
427 segment_list->plugin = sr_policy->plugin;
428 segment_list->plugin_mem = sr_policy->plugin_mem;
430 plugin->creation (sr_policy);
434 dpo_reset (&segment_list->bsid_dpo);
435 dpo_reset (&segment_list->ip6_dpo);
436 dpo_reset (&segment_list->ip4_dpo);
440 if (!sr_policy->plugin)
442 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
443 DPO_PROTO_IP6, segment_list - sm->sid_lists);
444 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
445 DPO_PROTO_IP4, segment_list - sm->sid_lists);
446 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
447 DPO_PROTO_IP6, segment_list - sm->sid_lists);
451 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
452 segment_list - sm->sid_lists);
453 dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
454 segment_list - sm->sid_lists);
455 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
456 segment_list - sm->sid_lists);
461 if (!sr_policy->plugin)
463 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
464 DPO_PROTO_IP6, segment_list - sm->sid_lists);
465 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
466 DPO_PROTO_IP6, segment_list - sm->sid_lists);
470 dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
471 segment_list - sm->sid_lists);
472 dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
473 segment_list - sm->sid_lists);
481 * @brief Updates the Load-Balancer after an SR Policy change
483 * @param sr_policy is the modified SR Policy
486 update_lb (ip6_sr_policy_t * sr_policy)
488 flow_hash_config_t fhc;
490 ip6_sr_sl_t *segment_list;
491 ip6_sr_main_t *sm = &sr_main;
492 load_balance_path_t path;
493 path.path_index = FIB_NODE_INDEX_INVALID;
494 load_balance_path_t *ip4_path_vector = 0;
495 load_balance_path_t *ip6_path_vector = 0;
496 load_balance_path_t *b_path_vector = 0;
498 /* In case LB does not exist, create it */
499 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
502 .fp_proto = FIB_PROTOCOL_IP6,
505 .ip6 = sr_policy->bsid,
509 /* Add FIB entry for BSID */
510 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
513 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
514 load_balance_create (0, DPO_PROTO_IP6, fhc));
516 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
517 load_balance_create (0, DPO_PROTO_IP6, fhc));
519 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
520 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
521 sr_policy->fib_table),
523 FIB_ENTRY_FLAG_EXCLUSIVE,
524 &sr_policy->bsid_dpo);
526 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
529 FIB_ENTRY_FLAG_EXCLUSIVE,
530 &sr_policy->ip6_dpo);
532 if (sr_policy->is_encap)
534 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
535 load_balance_create (0, DPO_PROTO_IP4, fhc));
537 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
540 FIB_ENTRY_FLAG_EXCLUSIVE,
541 &sr_policy->ip4_dpo);
546 /* Create the LB path vector */
547 vec_foreach (sl_index, sr_policy->segments_lists)
549 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
550 path.path_dpo = segment_list->bsid_dpo;
551 path.path_weight = segment_list->weight;
552 vec_add1 (b_path_vector, path);
553 path.path_dpo = segment_list->ip6_dpo;
554 vec_add1 (ip6_path_vector, path);
555 if (sr_policy->is_encap)
557 path.path_dpo = segment_list->ip4_dpo;
558 vec_add1 (ip4_path_vector, path);
562 /* Update LB multipath */
563 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
564 LOAD_BALANCE_FLAG_NONE);
565 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
566 LOAD_BALANCE_FLAG_NONE);
567 if (sr_policy->is_encap)
568 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
569 LOAD_BALANCE_FLAG_NONE);
572 vec_free (b_path_vector);
573 vec_free (ip6_path_vector);
574 vec_free (ip4_path_vector);
578 * @brief Updates the Replicate DPO after an SR Policy change
580 * @param sr_policy is the modified SR Policy (type spray)
583 update_replicate (ip6_sr_policy_t * sr_policy)
586 ip6_sr_sl_t *segment_list;
587 ip6_sr_main_t *sm = &sr_main;
588 load_balance_path_t path;
589 path.path_index = FIB_NODE_INDEX_INVALID;
590 load_balance_path_t *b_path_vector = 0;
591 load_balance_path_t *ip6_path_vector = 0;
592 load_balance_path_t *ip4_path_vector = 0;
594 /* In case LB does not exist, create it */
595 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
597 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
598 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
600 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
601 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
603 /* Update FIB entry's DPO to point to SR without LB */
605 .fp_proto = FIB_PROTOCOL_IP6,
608 .ip6 = sr_policy->bsid,
611 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
612 sr_policy->fib_table),
614 FIB_ENTRY_FLAG_EXCLUSIVE,
615 &sr_policy->bsid_dpo);
617 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
620 FIB_ENTRY_FLAG_EXCLUSIVE,
621 &sr_policy->ip6_dpo);
623 if (sr_policy->is_encap)
625 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
626 replicate_create (0, DPO_PROTO_IP4));
628 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
631 FIB_ENTRY_FLAG_EXCLUSIVE,
632 &sr_policy->ip4_dpo);
637 /* Create the replicate path vector */
638 path.path_weight = 1;
639 vec_foreach (sl_index, sr_policy->segments_lists)
641 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
642 path.path_dpo = segment_list->bsid_dpo;
643 vec_add1 (b_path_vector, path);
644 path.path_dpo = segment_list->ip6_dpo;
645 vec_add1 (ip6_path_vector, path);
646 if (sr_policy->is_encap)
648 path.path_dpo = segment_list->ip4_dpo;
649 vec_add1 (ip4_path_vector, path);
653 /* Update replicate multipath */
654 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
655 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
656 if (sr_policy->is_encap)
657 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
660 /******************************* SR rewrite API *******************************/
661 /* Three functions for handling sr policies:
665 * All of them are API. CLI function on sr_policy_command_fn */
668 * @brief Create a new SR policy
670 * @param bsid is the bindingSID of the SR Policy
671 * @param segments is a vector of IPv6 address composing the segment list
672 * @param encap_src is a encaps IPv6 source addr. optional.
673 * @param weight is the weight of the sid list. optional.
674 * @param behavior is the behavior of the SR policy. (default//spray)
675 * @param fib_table is the VRF where to install the FIB entry for the BSID
676 * @param is_encap (bool) whether SR policy should behave as Encap/SRH
679 * @return 0 if correct, else error
682 sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments,
683 ip6_address_t *encap_src, u32 weight, u8 type, u32 fib_table,
684 u8 is_encap, u16 plugin, void *ls_plugin_mem)
686 ip6_sr_main_t *sm = &sr_main;
687 ip6_sr_policy_t *sr_policy = 0;
690 /* Search for existing keys (BSID) */
691 p = mhash_get (&sm->sr_policies_index_hash, bsid);
694 /* Add SR policy that already exists; complain */
698 /* Search collision in FIB entries */
699 /* Explanation: It might be possible that some other entity has already
700 * created a route for the BSID. This in theory is impossible, but in
701 * practise we could see it. Assert it and scream if needed */
703 .fp_proto = FIB_PROTOCOL_IP6,
710 /* Lookup the FIB index associated to the table selected */
711 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
712 (fib_table != (u32) ~ 0 ? fib_table : 0));
716 /* Lookup whether there exists an entry for the BSID */
717 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
718 if (FIB_NODE_INDEX_INVALID != fei)
719 return -12; //There is an entry for such lookup
721 /* Add an SR policy object */
722 pool_get (sm->sr_policies, sr_policy);
723 clib_memset (sr_policy, 0, sizeof (*sr_policy));
724 clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
725 sr_policy->type = type;
726 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
727 sr_policy->is_encap = is_encap;
731 sr_policy->plugin = plugin;
732 sr_policy->plugin_mem = ls_plugin_mem;
736 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
739 /* Create a segment list and add the index to the SR policy */
740 create_sl (sr_policy, segments, encap_src, weight, is_encap);
742 /* If FIB doesnt exist, create them */
743 if (sm->fib_table_ip6 == (u32) ~ 0)
745 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
747 "SRv6 steering of IP6 prefixes through BSIDs");
748 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
750 "SRv6 steering of IP4 prefixes through BSIDs");
753 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
754 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
755 sr_policy->type == SR_POLICY_TYPE_TEF)
756 update_lb (sr_policy);
757 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
758 update_replicate (sr_policy);
763 * @brief Delete a SR policy
765 * @param bsid is the bindingSID of the SR Policy
766 * @param index is the index of the SR policy
768 * @return 0 if correct, else error
771 sr_policy_del (ip6_address_t * bsid, u32 index)
773 ip6_sr_main_t *sm = &sr_main;
774 ip6_sr_policy_t *sr_policy = 0;
775 ip6_sr_sl_t *segment_list;
781 p = mhash_get (&sm->sr_policies_index_hash, bsid);
783 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
789 sr_policy = pool_elt_at_index (sm->sr_policies, index);
792 /* Remove BindingSID FIB entry */
794 .fp_proto = FIB_PROTOCOL_IP6,
797 .ip6 = sr_policy->bsid,
802 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
803 sr_policy->fib_table),
804 &pfx, FIB_SOURCE_SR);
806 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
808 if (sr_policy->is_encap)
809 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
811 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
813 dpo_reset (&sr_policy->bsid_dpo);
814 dpo_reset (&sr_policy->ip4_dpo);
815 dpo_reset (&sr_policy->ip6_dpo);
818 /* Clean SID Lists */
819 vec_foreach (sl_index, sr_policy->segments_lists)
821 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
822 vec_free (segment_list->segments);
823 vec_free (segment_list->rewrite);
824 if (!sr_policy->is_encap)
825 vec_free (segment_list->rewrite_bsid);
826 pool_put_index (sm->sid_lists, *sl_index);
829 if (sr_policy->plugin)
831 sr_policy_fn_registration_t *plugin = 0;
834 pool_elt_at_index (sm->policy_plugin_functions,
835 sr_policy->plugin - SR_BEHAVIOR_LAST);
837 plugin->removal (sr_policy);
838 sr_policy->plugin = 0;
839 sr_policy->plugin_mem = NULL;
842 /* Remove SR policy entry */
843 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
844 pool_put (sm->sr_policies, sr_policy);
846 /* If FIB empty unlock it */
847 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
849 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
850 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
851 sm->fib_table_ip6 = (u32) ~ 0;
852 sm->fib_table_ip4 = (u32) ~ 0;
859 * @brief Modify an existing SR policy
861 * The possible modifications are adding a new Segment List, modifying an
862 * existing Segment List (modify the weight only) and delete a given
863 * Segment List from the SR Policy.
865 * @param bsid is the bindingSID of the SR Policy
866 * @param index is the index of the SR policy
867 * @param fib_table is the VRF where to install the FIB entry for the BSID
868 * @param operation is the operation to perform (among the top ones)
869 * @param segments is a vector of IPv6 address composing the segment list
870 * @param encap_src is a encaps IPv6 source addr. optional.
871 * @param sl_index is the index of the Segment List to modify/delete
872 * @param weight is the weight of the sid list. optional.
873 * @param is_encap Mode. Encapsulation or SRH insertion.
875 * @return 0 if correct, else error
878 sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation,
879 ip6_address_t *segments, ip6_address_t *encap_src, u32 sl_index,
882 ip6_sr_main_t *sm = &sr_main;
883 ip6_sr_policy_t *sr_policy = 0;
884 ip6_sr_sl_t *segment_list;
885 u32 *sl_index_iterate;
890 p = mhash_get (&sm->sr_policies_index_hash, bsid);
892 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
898 sr_policy = pool_elt_at_index (sm->sr_policies, index);
901 if (operation == 1) /* Add SR List to an existing SR policy */
903 /* Create the new SL */
904 segment_list = create_sl (sr_policy, segments, encap_src, weight,
905 sr_policy->is_encap);
907 /* Create a new LB DPO */
908 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
909 update_lb (sr_policy);
910 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
911 update_replicate (sr_policy);
913 else if (operation == 2) /* Delete SR List from an existing SR policy */
915 /* Check that currently there are more than one SID list */
916 if (vec_len (sr_policy->segments_lists) == 1)
919 /* Check that the SR list does exist and is assigned to the sr policy */
920 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
921 if (*sl_index_iterate == sl_index)
924 if (*sl_index_iterate != sl_index)
927 /* Remove the lucky SR list that is being kicked out */
928 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
929 vec_free (segment_list->segments);
930 vec_free (segment_list->rewrite);
931 if (!sr_policy->is_encap)
932 vec_free (segment_list->rewrite_bsid);
933 pool_put_index (sm->sid_lists, sl_index);
934 vec_del1 (sr_policy->segments_lists,
935 sl_index_iterate - sr_policy->segments_lists);
937 /* Create a new LB DPO */
938 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
939 update_lb (sr_policy);
940 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
941 update_replicate (sr_policy);
943 else if (operation == 3) /* Modify the weight of an existing SR List */
945 /* Find the corresponding SL */
946 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
947 if (*sl_index_iterate == sl_index)
950 if (*sl_index_iterate != sl_index)
953 /* Change the weight */
954 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
955 segment_list->weight = weight;
958 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
959 update_lb (sr_policy);
961 else /* Incorrect op. */
968 * @brief CLI for 'sr policies' command family
970 static clib_error_t *
971 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
972 vlib_cli_command_t * cmd)
974 ip6_sr_main_t *sm = &sr_main;
976 char is_del = 0, is_add = 0, is_mod = 0;
978 ip6_address_t bsid, next_address, src_v6addr;
979 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
980 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
981 ip6_address_t *segments = 0, *this_seg;
984 u8 type = SR_POLICY_TYPE_DEFAULT;
986 void *ls_plugin_mem = 0;
987 ip6_address_t *encap_src = 0;
989 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
991 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
993 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
995 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
998 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
1000 else if (!is_add && !policy_set
1001 && unformat (input, "index %d", &sr_policy_index))
1003 else if (unformat (input, "weight %d", &weight));
1005 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
1007 vec_add2 (segments, this_seg, 1);
1008 clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
1009 sizeof (*this_seg));
1011 else if (unformat (input, "v6src %U", unformat_ip6_address, &src_v6addr))
1013 encap_src = &src_v6addr;
1015 else if (unformat (input, "add sl"))
1017 else if (unformat (input, "del sl index %d", &sl_index))
1019 else if (unformat (input, "mod sl index %d", &sl_index))
1021 else if (fib_table == (u32) ~ 0
1022 && unformat (input, "fib-table %d", &fib_table));
1023 else if (unformat (input, "encap"))
1025 else if (unformat (input, "insert"))
1027 else if (unformat (input, "spray"))
1028 type = SR_POLICY_TYPE_SPRAY;
1029 else if (unformat (input, "tef"))
1030 type = SR_POLICY_TYPE_TEF;
1031 else if (!behavior && unformat (input, "behavior"))
1033 sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
1034 sr_policy_fn_registration_t **plugin_it = 0;
1037 pool_foreach (plugin, sm->policy_plugin_functions)
1039 vec_add1 (vec_plugins, plugin);
1043 vec_foreach (plugin_it, vec_plugins)
1046 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
1048 behavior = (*plugin_it)->sr_policy_function_number;
1055 return clib_error_return (0, "Invalid behavior");
1062 if (!is_add && !is_mod && !is_del)
1063 return clib_error_return (0, "Incorrect CLI");
1066 return clib_error_return (0, "No SR policy BSID or index specified");
1070 if (behavior && vec_len (segments) == 0)
1072 vec_add2 (segments, this_seg, 1);
1073 clib_memset (this_seg, 0, sizeof (*this_seg));
1076 if (vec_len (segments) == 0)
1077 return clib_error_return (0, "No Segment List specified");
1079 rv = sr_policy_add (&bsid, segments, encap_src, weight, type, fib_table,
1080 is_encap, behavior, ls_plugin_mem);
1082 vec_free (segments);
1085 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
1090 return clib_error_return (0, "No SL modification specified");
1091 if (operation != 1 && sl_index == (u32) ~ 0)
1092 return clib_error_return (0, "No Segment List index specified");
1093 if (operation == 1 && vec_len (segments) == 0)
1094 return clib_error_return (0, "No Segment List specified");
1095 if (operation == 3 && weight == (u32) ~ 0)
1096 return clib_error_return (0, "No new weight for the SL specified");
1098 rv = sr_policy_mod ((sr_policy_index != (u32) ~0 ? NULL : &bsid),
1099 sr_policy_index, fib_table, operation, segments,
1100 encap_src, sl_index, weight);
1103 vec_free (segments);
1113 return clib_error_return (0,
1114 "There is already a FIB entry for the BindingSID address.\n"
1115 "The SR policy could not be created.");
1117 return clib_error_return (0, "The specified FIB table does not exist.");
1119 return clib_error_return (0,
1120 "The selected SR policy only contains ONE segment list. "
1121 "Please remove the SR policy instead");
1123 return clib_error_return (0,
1124 "Could not delete the segment list. "
1125 "It is not associated with that SR policy.");
1127 return clib_error_return (0,
1128 "Could not modify the segment list. "
1129 "The given SL is not associated with such SR policy.");
1131 return clib_error_return (0, "BUG: sr policy returns %d", rv);
1137 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1138 .path = "sr policy",
1139 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
1140 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
1142 "Manipulation of SR policies.\n"
1143 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
1144 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
1145 "Segment Routing policies might be of type encapsulation or srh insertion\n"
1146 "Each SR policy will be associated with a unique BindingSID.\n"
1147 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
1148 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
1149 "The add command will create a SR policy with its first segment list (sl)\n"
1150 "The mod command allows you to add, remove, or modify the existing segment lists\n"
1151 "within an SR policy.\n"
1152 "The del command allows you to delete a SR policy along with all its associated\n"
1154 .function = sr_policy_command_fn,
1159 * @brief CLI to display onscreen all the SR policies
1161 static clib_error_t *
1162 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
1163 vlib_cli_command_t * cmd)
1165 ip6_sr_main_t *sm = &sr_main;
1167 ip6_sr_sl_t *segment_list = 0;
1168 ip6_sr_policy_t *sr_policy = 0;
1169 ip6_sr_policy_t **vec_policies = 0;
1170 ip6_address_t *addr;
1174 vlib_cli_output (vm, "SR policies:");
1177 pool_foreach (sr_policy, sm->sr_policies)
1178 {vec_add1 (vec_policies, sr_policy); }
1181 vec_foreach_index (i, vec_policies)
1183 sr_policy = vec_policies[i];
1184 vlib_cli_output (vm, "[%u].-\tBSID: %U",
1185 (u32) (sr_policy - sm->sr_policies),
1186 format_ip6_address, &sr_policy->bsid);
1187 vlib_cli_output (vm, "\tBehavior: %s",
1188 (sr_policy->is_encap ? "Encapsulation" :
1190 if (sr_policy->is_encap)
1192 vlib_cli_output (vm, "\tEncapSrcIP: %U", format_ip6_address,
1193 &sr_policy->encap_src);
1195 switch (sr_policy->type)
1197 case SR_POLICY_TYPE_SPRAY:
1198 vlib_cli_output (vm, "\tType: %s", "Spray");
1200 case SR_POLICY_TYPE_TEF:
1201 vlib_cli_output (vm, "\tType: %s",
1202 "TEF (Timestamp, Encapsulate, and Forward)");
1205 vlib_cli_output (vm, "\tType: %s", "Default");
1208 vlib_cli_output (vm, "\tFIB table: %u",
1209 (sr_policy->fib_table !=
1210 (u32) ~ 0 ? sr_policy->fib_table : 0));
1211 vlib_cli_output (vm, "\tSegment Lists:");
1212 vec_foreach (sl_index, sr_policy->segments_lists)
1215 s = format (s, "\t[%u].- ", *sl_index);
1216 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1217 s = format (s, "< ");
1218 vec_foreach (addr, segment_list->segments)
1220 s = format (s, "%U, ", format_ip6_address, addr);
1222 s = format (s, "\b\b > ");
1223 s = format (s, "weight: %u", segment_list->weight);
1224 vlib_cli_output (vm, " %v", s);
1226 vlib_cli_output (vm, "-----------");
1232 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1233 .path = "show sr policies",
1234 .short_help = "show sr policies",
1235 .function = show_sr_policies_command_fn,
1240 * @brief CLI to display onscreen the SR encaps source addr
1242 static clib_error_t *
1243 show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
1244 vlib_cli_command_t * cmd)
1246 vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
1247 sr_get_encaps_source ());
1253 VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
1254 .path = "show sr encaps source addr",
1255 .short_help = "show sr encaps source addr",
1256 .function = show_sr_encaps_source_command_fn,
1261 * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
1263 static clib_error_t *
1264 show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
1265 unformat_input_t * input,
1266 vlib_cli_command_t * cmd)
1268 vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
1274 VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
1275 .path = "show sr encaps hop-limit",
1276 .short_help = "show sr encaps hop-limit",
1277 .function = show_sr_encaps_hop_limit_command_fn,
1281 /*************************** SR rewrite graph node ****************************/
1283 * @brief Trace for the SR Policy Rewrite graph node
1286 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1289 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1290 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1291 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1294 (s, "SR-policy-rewrite: src %U dst %U",
1295 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1300 * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
1302 static_always_inline void
1303 srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1306 ip6_sr_header_t *srh;
1307 ip6_sr_pt_tlv_t *srh_pt_tlv;
1309 sr_pt_iface_t *ls = 0;
1311 srh = (ip6_sr_header_t *) (ip0 + 1);
1314 (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
1315 sizeof (ip6_sr_header_t) +
1316 sizeof (ip6_address_t) * (srh->last_entry + 1));
1318 unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
1319 srh_pt_tlv->t64.sec = clib_host_to_net_u32 (ts.sec);
1320 srh_pt_tlv->t64.nsec = clib_host_to_net_u32 (ts.nsec);
1321 ls = sr_pt_find_iface (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1324 id_ld = ls->id << 4;
1325 id_ld |= ls->ingress_load;
1326 srh_pt_tlv->id_ld = clib_host_to_net_u16 (id_ld);
1331 * @brief IPv6 encapsulation processing as per RFC2473
1333 static_always_inline void
1334 encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
1335 ip6_header_t *ip0, ip6_header_t *ip0_encap,
1341 ip0_encap->hop_limit -= 1;
1343 ip0->payload_length + sizeof (ip6_header_t) +
1344 clib_net_to_host_u16 (ip0_encap->payload_length);
1345 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1347 flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1348 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1350 (clib_net_to_host_u32 (
1351 ip0_encap->ip_version_traffic_class_and_flow_label) &
1353 (flow_label & 0x0000ffff));
1354 if (policy_type == SR_POLICY_TYPE_TEF)
1355 srv6_tef_behavior (node, b0, ip0);
1359 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1362 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1363 vlib_frame_t * from_frame)
1365 ip6_sr_main_t *sm = &sr_main;
1366 u32 n_left_from, next_index, *from, *to_next;
1368 from = vlib_frame_vector_args (from_frame);
1369 n_left_from = from_frame->n_vectors;
1371 next_index = node->cached_next_index;
1373 int encap_pkts = 0, bsid_pkts = 0;
1375 while (n_left_from > 0)
1379 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1382 while (n_left_from >= 8 && n_left_to_next >= 4)
1384 u32 bi0, bi1, bi2, bi3;
1385 vlib_buffer_t *b0, *b1, *b2, *b3;
1386 u32 next0, next1, next2, next3;
1387 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1388 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1389 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1390 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1392 /* Prefetch next iteration. */
1394 vlib_buffer_t *p4, *p5, *p6, *p7;
1396 p4 = vlib_get_buffer (vm, from[4]);
1397 p5 = vlib_get_buffer (vm, from[5]);
1398 p6 = vlib_get_buffer (vm, from[6]);
1399 p7 = vlib_get_buffer (vm, from[7]);
1401 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1402 vlib_prefetch_buffer_header (p4, LOAD);
1403 vlib_prefetch_buffer_header (p5, LOAD);
1404 vlib_prefetch_buffer_header (p6, LOAD);
1405 vlib_prefetch_buffer_header (p7, LOAD);
1407 clib_prefetch_store (p4->data);
1408 clib_prefetch_store (p5->data);
1409 clib_prefetch_store (p6->data);
1410 clib_prefetch_store (p7->data);
1413 to_next[0] = bi0 = from[0];
1414 to_next[1] = bi1 = from[1];
1415 to_next[2] = bi2 = from[2];
1416 to_next[3] = bi3 = from[3];
1420 n_left_to_next -= 4;
1422 b0 = vlib_get_buffer (vm, bi0);
1423 b1 = vlib_get_buffer (vm, bi1);
1424 b2 = vlib_get_buffer (vm, bi2);
1425 b3 = vlib_get_buffer (vm, bi3);
1428 pool_elt_at_index (sm->sid_lists,
1429 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1431 pool_elt_at_index (sm->sid_lists,
1432 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1434 pool_elt_at_index (sm->sid_lists,
1435 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1437 pool_elt_at_index (sm->sid_lists,
1438 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1440 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1441 vec_len (sl0->rewrite));
1442 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1443 vec_len (sl1->rewrite));
1444 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1445 vec_len (sl2->rewrite));
1446 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1447 vec_len (sl3->rewrite));
1449 ip0_encap = vlib_buffer_get_current (b0);
1450 ip1_encap = vlib_buffer_get_current (b1);
1451 ip2_encap = vlib_buffer_get_current (b2);
1452 ip3_encap = vlib_buffer_get_current (b3);
1454 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1455 sl0->rewrite, vec_len (sl0->rewrite));
1456 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1457 sl1->rewrite, vec_len (sl1->rewrite));
1458 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1459 sl2->rewrite, vec_len (sl2->rewrite));
1460 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1461 sl3->rewrite, vec_len (sl3->rewrite));
1463 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1464 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1465 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1466 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1468 ip0 = vlib_buffer_get_current (b0);
1469 ip1 = vlib_buffer_get_current (b1);
1470 ip2 = vlib_buffer_get_current (b2);
1471 ip3 = vlib_buffer_get_current (b3);
1473 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1474 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
1475 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
1476 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
1478 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1479 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1480 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1481 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1483 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1485 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1487 sr_policy_rewrite_trace_t *tr =
1488 vlib_add_trace (vm, node, b0, sizeof (*tr));
1489 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1490 sizeof (tr->src.as_u8));
1491 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1492 sizeof (tr->dst.as_u8));
1495 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1497 sr_policy_rewrite_trace_t *tr =
1498 vlib_add_trace (vm, node, b1, sizeof (*tr));
1499 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1500 sizeof (tr->src.as_u8));
1501 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1502 sizeof (tr->dst.as_u8));
1505 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1507 sr_policy_rewrite_trace_t *tr =
1508 vlib_add_trace (vm, node, b2, sizeof (*tr));
1509 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1510 sizeof (tr->src.as_u8));
1511 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1512 sizeof (tr->dst.as_u8));
1515 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1517 sr_policy_rewrite_trace_t *tr =
1518 vlib_add_trace (vm, node, b3, sizeof (*tr));
1519 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1520 sizeof (tr->src.as_u8));
1521 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1522 sizeof (tr->dst.as_u8));
1527 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1528 n_left_to_next, bi0, bi1, bi2, bi3,
1529 next0, next1, next2, next3);
1532 /* Single loop for potentially the last three packets */
1533 while (n_left_from > 0 && n_left_to_next > 0)
1537 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1539 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1546 n_left_to_next -= 1;
1547 b0 = vlib_get_buffer (vm, bi0);
1550 pool_elt_at_index (sm->sid_lists,
1551 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1552 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1553 vec_len (sl0->rewrite));
1555 ip0_encap = vlib_buffer_get_current (b0);
1557 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1558 sl0->rewrite, vec_len (sl0->rewrite));
1559 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1561 ip0 = vlib_buffer_get_current (b0);
1563 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
1565 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1567 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1568 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1570 sr_policy_rewrite_trace_t *tr =
1571 vlib_add_trace (vm, node, b0, sizeof (*tr));
1572 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1573 sizeof (tr->src.as_u8));
1574 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1575 sizeof (tr->dst.as_u8));
1579 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1580 n_left_to_next, bi0, next0);
1583 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1586 /* Update counters */
1587 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1588 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1590 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1591 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1594 return from_frame->n_vectors;
1598 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1599 .function = sr_policy_rewrite_encaps,
1600 .name = "sr-pl-rewrite-encaps",
1601 .vector_size = sizeof (u32),
1602 .format_trace = format_sr_policy_rewrite_trace,
1603 .type = VLIB_NODE_TYPE_INTERNAL,
1604 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1605 .error_strings = sr_policy_rewrite_error_strings,
1606 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1608 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1609 foreach_sr_policy_rewrite_next
1616 * @brief IPv4 encapsulation processing as per RFC2473
1618 static_always_inline void
1619 encaps_processing_v4 (vlib_node_runtime_t * node,
1621 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1624 ip6_sr_header_t *sr0;
1629 /* Inner IPv4: Decrement TTL & update checksum */
1630 ip0_encap->ttl -= 1;
1631 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1632 checksum0 += checksum0 >= 0xffff;
1633 ip0_encap->checksum = checksum0;
1635 /* Outer IPv6: Update length, FL, proto */
1636 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1637 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1638 flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
1639 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
1640 0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
1641 (flow_label & 0x0000ffff));
1642 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1644 sr0 = (void *) (ip0 + 1);
1645 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1648 ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1652 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1655 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1656 vlib_frame_t * from_frame)
1658 ip6_sr_main_t *sm = &sr_main;
1659 u32 n_left_from, next_index, *from, *to_next;
1661 from = vlib_frame_vector_args (from_frame);
1662 n_left_from = from_frame->n_vectors;
1664 next_index = node->cached_next_index;
1666 int encap_pkts = 0, bsid_pkts = 0;
1668 while (n_left_from > 0)
1672 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1675 while (n_left_from >= 8 && n_left_to_next >= 4)
1677 u32 bi0, bi1, bi2, bi3;
1678 vlib_buffer_t *b0, *b1, *b2, *b3;
1679 u32 next0, next1, next2, next3;
1680 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1681 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1682 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1683 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1685 /* Prefetch next iteration. */
1687 vlib_buffer_t *p4, *p5, *p6, *p7;
1689 p4 = vlib_get_buffer (vm, from[4]);
1690 p5 = vlib_get_buffer (vm, from[5]);
1691 p6 = vlib_get_buffer (vm, from[6]);
1692 p7 = vlib_get_buffer (vm, from[7]);
1694 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1695 vlib_prefetch_buffer_header (p4, LOAD);
1696 vlib_prefetch_buffer_header (p5, LOAD);
1697 vlib_prefetch_buffer_header (p6, LOAD);
1698 vlib_prefetch_buffer_header (p7, LOAD);
1700 clib_prefetch_store (p4->data);
1701 clib_prefetch_store (p5->data);
1702 clib_prefetch_store (p6->data);
1703 clib_prefetch_store (p7->data);
1706 to_next[0] = bi0 = from[0];
1707 to_next[1] = bi1 = from[1];
1708 to_next[2] = bi2 = from[2];
1709 to_next[3] = bi3 = from[3];
1713 n_left_to_next -= 4;
1715 b0 = vlib_get_buffer (vm, bi0);
1716 b1 = vlib_get_buffer (vm, bi1);
1717 b2 = vlib_get_buffer (vm, bi2);
1718 b3 = vlib_get_buffer (vm, bi3);
1721 pool_elt_at_index (sm->sid_lists,
1722 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1724 pool_elt_at_index (sm->sid_lists,
1725 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1727 pool_elt_at_index (sm->sid_lists,
1728 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1730 pool_elt_at_index (sm->sid_lists,
1731 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1732 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1733 vec_len (sl0->rewrite));
1734 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1735 vec_len (sl1->rewrite));
1736 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1737 vec_len (sl2->rewrite));
1738 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1739 vec_len (sl3->rewrite));
1741 ip0_encap = vlib_buffer_get_current (b0);
1742 ip1_encap = vlib_buffer_get_current (b1);
1743 ip2_encap = vlib_buffer_get_current (b2);
1744 ip3_encap = vlib_buffer_get_current (b3);
1746 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1747 sl0->rewrite, vec_len (sl0->rewrite));
1748 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1749 sl1->rewrite, vec_len (sl1->rewrite));
1750 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1751 sl2->rewrite, vec_len (sl2->rewrite));
1752 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1753 sl3->rewrite, vec_len (sl3->rewrite));
1755 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1756 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1757 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1758 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1760 ip0 = vlib_buffer_get_current (b0);
1761 ip1 = vlib_buffer_get_current (b1);
1762 ip2 = vlib_buffer_get_current (b2);
1763 ip3 = vlib_buffer_get_current (b3);
1765 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1766 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1767 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1768 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1770 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1771 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
1772 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
1773 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
1775 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1777 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1779 sr_policy_rewrite_trace_t *tr =
1780 vlib_add_trace (vm, node, b0, sizeof (*tr));
1781 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1782 sizeof (tr->src.as_u8));
1783 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1784 sizeof (tr->dst.as_u8));
1787 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1789 sr_policy_rewrite_trace_t *tr =
1790 vlib_add_trace (vm, node, b1, sizeof (*tr));
1791 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
1792 sizeof (tr->src.as_u8));
1793 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
1794 sizeof (tr->dst.as_u8));
1797 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1799 sr_policy_rewrite_trace_t *tr =
1800 vlib_add_trace (vm, node, b2, sizeof (*tr));
1801 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
1802 sizeof (tr->src.as_u8));
1803 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
1804 sizeof (tr->dst.as_u8));
1807 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1809 sr_policy_rewrite_trace_t *tr =
1810 vlib_add_trace (vm, node, b3, sizeof (*tr));
1811 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
1812 sizeof (tr->src.as_u8));
1813 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
1814 sizeof (tr->dst.as_u8));
1819 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1820 n_left_to_next, bi0, bi1, bi2, bi3,
1821 next0, next1, next2, next3);
1824 /* Single loop for potentially the last three packets */
1825 while (n_left_from > 0 && n_left_to_next > 0)
1829 ip6_header_t *ip0 = 0;
1830 ip4_header_t *ip0_encap = 0;
1832 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1839 n_left_to_next -= 1;
1840 b0 = vlib_get_buffer (vm, bi0);
1843 pool_elt_at_index (sm->sid_lists,
1844 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1845 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1846 vec_len (sl0->rewrite));
1848 ip0_encap = vlib_buffer_get_current (b0);
1850 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1851 sl0->rewrite, vec_len (sl0->rewrite));
1852 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1854 ip0 = vlib_buffer_get_current (b0);
1856 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1858 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
1860 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1861 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1863 sr_policy_rewrite_trace_t *tr =
1864 vlib_add_trace (vm, node, b0, sizeof (*tr));
1865 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
1866 sizeof (tr->src.as_u8));
1867 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
1868 sizeof (tr->dst.as_u8));
1872 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1873 n_left_to_next, bi0, next0);
1876 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1879 /* Update counters */
1880 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1881 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1883 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1884 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1887 return from_frame->n_vectors;
1891 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1892 .function = sr_policy_rewrite_encaps_v4,
1893 .name = "sr-pl-rewrite-encaps-v4",
1894 .vector_size = sizeof (u32),
1895 .format_trace = format_sr_policy_rewrite_trace,
1896 .type = VLIB_NODE_TYPE_INTERNAL,
1897 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1898 .error_strings = sr_policy_rewrite_error_strings,
1899 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1901 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1902 foreach_sr_policy_rewrite_next
1909 ip_flow_hash (void *data)
1911 ip4_header_t *iph = (ip4_header_t *) data;
1913 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1914 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1916 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1922 return (*((u64 *) m) & 0xffffffffffff);
1926 l2_flow_hash (vlib_buffer_t * b0)
1928 ethernet_header_t *eh;
1930 uword is_ip, eh_size;
1933 eh = vlib_buffer_get_current (b0);
1934 eh_type = clib_net_to_host_u16 (eh->type);
1935 eh_size = ethernet_buffer_header_size (b0);
1937 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1939 /* since we have 2 cache lines, use them */
1941 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1945 b = mac_to_u64 ((u8 *) eh->dst_address);
1946 c = mac_to_u64 ((u8 *) eh->src_address);
1947 hash_mix64 (a, b, c);
1953 * @brief Graph node for applying a SR policy into a L2 frame
1956 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1957 vlib_frame_t * from_frame)
1959 ip6_sr_main_t *sm = &sr_main;
1960 u32 n_left_from, next_index, *from, *to_next;
1962 from = vlib_frame_vector_args (from_frame);
1963 n_left_from = from_frame->n_vectors;
1965 next_index = node->cached_next_index;
1967 int encap_pkts = 0, bsid_pkts = 0;
1969 while (n_left_from > 0)
1973 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1976 while (n_left_from >= 8 && n_left_to_next >= 4)
1978 u32 bi0, bi1, bi2, bi3;
1979 vlib_buffer_t *b0, *b1, *b2, *b3;
1980 u32 next0, next1, next2, next3;
1981 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1982 ethernet_header_t *en0, *en1, *en2, *en3;
1983 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1984 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1985 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1986 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1987 u32 flow_label0, flow_label1, flow_label2, flow_label3;
1989 /* Prefetch next iteration. */
1991 vlib_buffer_t *p4, *p5, *p6, *p7;
1993 p4 = vlib_get_buffer (vm, from[4]);
1994 p5 = vlib_get_buffer (vm, from[5]);
1995 p6 = vlib_get_buffer (vm, from[6]);
1996 p7 = vlib_get_buffer (vm, from[7]);
1998 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1999 vlib_prefetch_buffer_header (p4, LOAD);
2000 vlib_prefetch_buffer_header (p5, LOAD);
2001 vlib_prefetch_buffer_header (p6, LOAD);
2002 vlib_prefetch_buffer_header (p7, LOAD);
2004 clib_prefetch_store (p4->data);
2005 clib_prefetch_store (p5->data);
2006 clib_prefetch_store (p6->data);
2007 clib_prefetch_store (p7->data);
2010 to_next[0] = bi0 = from[0];
2011 to_next[1] = bi1 = from[1];
2012 to_next[2] = bi2 = from[2];
2013 to_next[3] = bi3 = from[3];
2017 n_left_to_next -= 4;
2019 b0 = vlib_get_buffer (vm, bi0);
2020 b1 = vlib_get_buffer (vm, bi1);
2021 b2 = vlib_get_buffer (vm, bi2);
2022 b3 = vlib_get_buffer (vm, bi3);
2024 sp0 = pool_elt_at_index (sm->sr_policies,
2025 sm->sw_iface_sr_policies[vnet_buffer
2029 sp1 = pool_elt_at_index (sm->sr_policies,
2030 sm->sw_iface_sr_policies[vnet_buffer
2034 sp2 = pool_elt_at_index (sm->sr_policies,
2035 sm->sw_iface_sr_policies[vnet_buffer
2039 sp3 = pool_elt_at_index (sm->sr_policies,
2040 sm->sw_iface_sr_policies[vnet_buffer
2043 flow_label0 = l2_flow_hash (b0);
2044 flow_label1 = l2_flow_hash (b1);
2045 flow_label2 = l2_flow_hash (b2);
2046 flow_label3 = l2_flow_hash (b3);
2048 if (vec_len (sp0->segments_lists) == 1)
2049 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2052 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2053 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2054 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2055 (vec_len (sp0->segments_lists) - 1))];
2058 if (vec_len (sp1->segments_lists) == 1)
2059 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
2062 vnet_buffer (b1)->ip.flow_hash = flow_label1;
2063 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
2064 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
2065 (vec_len (sp1->segments_lists) - 1))];
2068 if (vec_len (sp2->segments_lists) == 1)
2069 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
2072 vnet_buffer (b2)->ip.flow_hash = flow_label2;
2073 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
2074 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
2075 (vec_len (sp2->segments_lists) - 1))];
2078 if (vec_len (sp3->segments_lists) == 1)
2079 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
2082 vnet_buffer (b3)->ip.flow_hash = flow_label3;
2083 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
2084 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
2085 (vec_len (sp3->segments_lists) - 1))];
2089 pool_elt_at_index (sm->sid_lists,
2090 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2092 pool_elt_at_index (sm->sid_lists,
2093 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2095 pool_elt_at_index (sm->sid_lists,
2096 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2098 pool_elt_at_index (sm->sid_lists,
2099 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2101 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2102 vec_len (sl0->rewrite));
2103 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2104 vec_len (sl1->rewrite));
2105 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2106 vec_len (sl2->rewrite));
2107 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2108 vec_len (sl3->rewrite));
2110 en0 = vlib_buffer_get_current (b0);
2111 en1 = vlib_buffer_get_current (b1);
2112 en2 = vlib_buffer_get_current (b2);
2113 en3 = vlib_buffer_get_current (b3);
2115 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2116 sl0->rewrite, vec_len (sl0->rewrite));
2117 clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
2118 sl1->rewrite, vec_len (sl1->rewrite));
2119 clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
2120 sl2->rewrite, vec_len (sl2->rewrite));
2121 clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
2122 sl3->rewrite, vec_len (sl3->rewrite));
2124 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2125 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2126 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2127 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2129 ip0 = vlib_buffer_get_current (b0);
2130 ip1 = vlib_buffer_get_current (b1);
2131 ip2 = vlib_buffer_get_current (b2);
2132 ip3 = vlib_buffer_get_current (b3);
2134 ip0->payload_length =
2135 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2136 ip1->payload_length =
2137 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
2138 ip2->payload_length =
2139 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
2140 ip3->payload_length =
2141 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
2143 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2145 sr0 = (void *) (ip0 + 1);
2146 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2149 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2151 if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
2153 sr1 = (void *) (ip1 + 1);
2154 sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2157 ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
2159 if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
2161 sr2 = (void *) (ip2 + 1);
2162 sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2165 ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
2167 if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
2169 sr3 = (void *) (ip3 + 1);
2170 sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2173 ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
2175 /* TC is set to 0 for all ethernet frames, should be taken from COS
2176 * od DSCP of encapsulated packet in the future */
2177 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2178 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2179 ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2180 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
2181 ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2182 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
2183 ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2184 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
2186 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2188 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2190 sr_policy_rewrite_trace_t *tr =
2191 vlib_add_trace (vm, node, b0, sizeof (*tr));
2192 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2193 sizeof (tr->src.as_u8));
2194 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2195 sizeof (tr->dst.as_u8));
2198 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2200 sr_policy_rewrite_trace_t *tr =
2201 vlib_add_trace (vm, node, b1, sizeof (*tr));
2202 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2203 sizeof (tr->src.as_u8));
2204 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2205 sizeof (tr->dst.as_u8));
2208 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2210 sr_policy_rewrite_trace_t *tr =
2211 vlib_add_trace (vm, node, b2, sizeof (*tr));
2212 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2213 sizeof (tr->src.as_u8));
2214 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2215 sizeof (tr->dst.as_u8));
2218 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2220 sr_policy_rewrite_trace_t *tr =
2221 vlib_add_trace (vm, node, b3, sizeof (*tr));
2222 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2223 sizeof (tr->src.as_u8));
2224 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2225 sizeof (tr->dst.as_u8));
2230 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2231 n_left_to_next, bi0, bi1, bi2, bi3,
2232 next0, next1, next2, next3);
2235 /* Single loop for potentially the last three packets */
2236 while (n_left_from > 0 && n_left_to_next > 0)
2240 ip6_header_t *ip0 = 0;
2241 ip6_sr_header_t *sr0;
2242 ethernet_header_t *en0;
2243 ip6_sr_policy_t *sp0;
2245 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2253 n_left_to_next -= 1;
2254 b0 = vlib_get_buffer (vm, bi0);
2256 /* Find the SR policy */
2257 sp0 = pool_elt_at_index (sm->sr_policies,
2258 sm->sw_iface_sr_policies[vnet_buffer
2261 flow_label0 = l2_flow_hash (b0);
2263 /* In case there is more than one SL, LB among them */
2264 if (vec_len (sp0->segments_lists) == 1)
2265 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
2268 vnet_buffer (b0)->ip.flow_hash = flow_label0;
2269 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2270 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
2271 (vec_len (sp0->segments_lists) - 1))];
2274 pool_elt_at_index (sm->sid_lists,
2275 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2276 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2277 vec_len (sl0->rewrite));
2279 en0 = vlib_buffer_get_current (b0);
2281 clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
2282 sl0->rewrite, vec_len (sl0->rewrite));
2284 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2286 ip0 = vlib_buffer_get_current (b0);
2288 ip0->payload_length =
2289 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
2291 if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
2293 sr0 = (void *) (ip0 + 1);
2294 sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2297 ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
2299 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
2300 0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
2302 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2303 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2305 sr_policy_rewrite_trace_t *tr =
2306 vlib_add_trace (vm, node, b0, sizeof (*tr));
2307 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2308 sizeof (tr->src.as_u8));
2309 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2310 sizeof (tr->dst.as_u8));
2314 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2315 n_left_to_next, bi0, next0);
2318 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2321 /* Update counters */
2322 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2323 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2325 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
2326 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2329 return from_frame->n_vectors;
2333 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
2334 .function = sr_policy_rewrite_encaps_l2,
2335 .name = "sr-pl-rewrite-encaps-l2",
2336 .vector_size = sizeof (u32),
2337 .format_trace = format_sr_policy_rewrite_trace,
2338 .type = VLIB_NODE_TYPE_INTERNAL,
2339 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2340 .error_strings = sr_policy_rewrite_error_strings,
2341 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2343 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2344 foreach_sr_policy_rewrite_next
2351 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2354 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2355 vlib_frame_t * from_frame)
2357 ip6_sr_main_t *sm = &sr_main;
2358 u32 n_left_from, next_index, *from, *to_next;
2360 from = vlib_frame_vector_args (from_frame);
2361 n_left_from = from_frame->n_vectors;
2363 next_index = node->cached_next_index;
2365 int insert_pkts = 0, bsid_pkts = 0;
2367 while (n_left_from > 0)
2371 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2374 while (n_left_from >= 8 && n_left_to_next >= 4)
2376 u32 bi0, bi1, bi2, bi3;
2377 vlib_buffer_t *b0, *b1, *b2, *b3;
2378 u32 next0, next1, next2, next3;
2379 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2380 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2381 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2382 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2383 u16 new_l0, new_l1, new_l2, new_l3;
2385 /* Prefetch next iteration. */
2387 vlib_buffer_t *p4, *p5, *p6, *p7;
2389 p4 = vlib_get_buffer (vm, from[4]);
2390 p5 = vlib_get_buffer (vm, from[5]);
2391 p6 = vlib_get_buffer (vm, from[6]);
2392 p7 = vlib_get_buffer (vm, from[7]);
2394 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2395 vlib_prefetch_buffer_header (p4, LOAD);
2396 vlib_prefetch_buffer_header (p5, LOAD);
2397 vlib_prefetch_buffer_header (p6, LOAD);
2398 vlib_prefetch_buffer_header (p7, LOAD);
2400 clib_prefetch_store (p4->data);
2401 clib_prefetch_store (p5->data);
2402 clib_prefetch_store (p6->data);
2403 clib_prefetch_store (p7->data);
2406 to_next[0] = bi0 = from[0];
2407 to_next[1] = bi1 = from[1];
2408 to_next[2] = bi2 = from[2];
2409 to_next[3] = bi3 = from[3];
2413 n_left_to_next -= 4;
2415 b0 = vlib_get_buffer (vm, bi0);
2416 b1 = vlib_get_buffer (vm, bi1);
2417 b2 = vlib_get_buffer (vm, bi2);
2418 b3 = vlib_get_buffer (vm, bi3);
2421 pool_elt_at_index (sm->sid_lists,
2422 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2424 pool_elt_at_index (sm->sid_lists,
2425 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2427 pool_elt_at_index (sm->sid_lists,
2428 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2430 pool_elt_at_index (sm->sid_lists,
2431 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2432 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2433 vec_len (sl0->rewrite));
2434 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2435 vec_len (sl1->rewrite));
2436 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2437 vec_len (sl2->rewrite));
2438 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2439 vec_len (sl3->rewrite));
2441 ip0 = vlib_buffer_get_current (b0);
2442 ip1 = vlib_buffer_get_current (b1);
2443 ip2 = vlib_buffer_get_current (b2);
2444 ip3 = vlib_buffer_get_current (b3);
2446 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2448 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2449 ip6_ext_header_len (ip0 + 1));
2451 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2453 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2455 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2456 ip6_ext_header_len (ip1 + 1));
2458 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2460 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2462 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2463 ip6_ext_header_len (ip2 + 1));
2465 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2467 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2469 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2470 ip6_ext_header_len (ip3 + 1));
2472 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2474 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2475 (void *) sr0 - (void *) ip0);
2476 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2477 (void *) sr1 - (void *) ip1);
2478 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2479 (void *) sr2 - (void *) ip2);
2480 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2481 (void *) sr3 - (void *) ip3);
2483 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2484 sl0->rewrite, vec_len (sl0->rewrite));
2485 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
2486 sl1->rewrite, vec_len (sl1->rewrite));
2487 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
2488 sl2->rewrite, vec_len (sl2->rewrite));
2489 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
2490 sl3->rewrite, vec_len (sl3->rewrite));
2492 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2493 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2494 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2495 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2497 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2498 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2499 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2500 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2502 ip0->hop_limit -= 1;
2503 ip1->hop_limit -= 1;
2504 ip2->hop_limit -= 1;
2505 ip3->hop_limit -= 1;
2508 clib_net_to_host_u16 (ip0->payload_length) +
2509 vec_len (sl0->rewrite);
2511 clib_net_to_host_u16 (ip1->payload_length) +
2512 vec_len (sl1->rewrite);
2514 clib_net_to_host_u16 (ip2->payload_length) +
2515 vec_len (sl2->rewrite);
2517 clib_net_to_host_u16 (ip3->payload_length) +
2518 vec_len (sl3->rewrite);
2520 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2521 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2522 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2523 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2525 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2526 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2527 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2528 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2530 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2531 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2532 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2533 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2534 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2535 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2536 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2537 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2539 ip0->dst_address.as_u64[0] =
2540 (sr0->segments + sr0->segments_left)->as_u64[0];
2541 ip0->dst_address.as_u64[1] =
2542 (sr0->segments + sr0->segments_left)->as_u64[1];
2543 ip1->dst_address.as_u64[0] =
2544 (sr1->segments + sr1->segments_left)->as_u64[0];
2545 ip1->dst_address.as_u64[1] =
2546 (sr1->segments + sr1->segments_left)->as_u64[1];
2547 ip2->dst_address.as_u64[0] =
2548 (sr2->segments + sr2->segments_left)->as_u64[0];
2549 ip2->dst_address.as_u64[1] =
2550 (sr2->segments + sr2->segments_left)->as_u64[1];
2551 ip3->dst_address.as_u64[0] =
2552 (sr3->segments + sr3->segments_left)->as_u64[0];
2553 ip3->dst_address.as_u64[1] =
2554 (sr3->segments + sr3->segments_left)->as_u64[1];
2556 ip6_ext_header_t *ip_ext;
2557 if (ip0 + 1 == (void *) sr0)
2559 sr0->protocol = ip0->protocol;
2560 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2564 ip_ext = (void *) (ip0 + 1);
2565 sr0->protocol = ip_ext->next_hdr;
2566 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2569 if (ip1 + 1 == (void *) sr1)
2571 sr1->protocol = ip1->protocol;
2572 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2576 ip_ext = (void *) (ip2 + 1);
2577 sr2->protocol = ip_ext->next_hdr;
2578 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2581 if (ip2 + 1 == (void *) sr2)
2583 sr2->protocol = ip2->protocol;
2584 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2588 ip_ext = (void *) (ip2 + 1);
2589 sr2->protocol = ip_ext->next_hdr;
2590 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2593 if (ip3 + 1 == (void *) sr3)
2595 sr3->protocol = ip3->protocol;
2596 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2600 ip_ext = (void *) (ip3 + 1);
2601 sr3->protocol = ip_ext->next_hdr;
2602 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2607 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2609 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2611 sr_policy_rewrite_trace_t *tr =
2612 vlib_add_trace (vm, node, b0, sizeof (*tr));
2613 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2614 sizeof (tr->src.as_u8));
2615 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2616 sizeof (tr->dst.as_u8));
2619 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2621 sr_policy_rewrite_trace_t *tr =
2622 vlib_add_trace (vm, node, b1, sizeof (*tr));
2623 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
2624 sizeof (tr->src.as_u8));
2625 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
2626 sizeof (tr->dst.as_u8));
2629 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2631 sr_policy_rewrite_trace_t *tr =
2632 vlib_add_trace (vm, node, b2, sizeof (*tr));
2633 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
2634 sizeof (tr->src.as_u8));
2635 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
2636 sizeof (tr->dst.as_u8));
2639 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2641 sr_policy_rewrite_trace_t *tr =
2642 vlib_add_trace (vm, node, b3, sizeof (*tr));
2643 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
2644 sizeof (tr->src.as_u8));
2645 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
2646 sizeof (tr->dst.as_u8));
2650 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2651 n_left_to_next, bi0, bi1, bi2, bi3,
2652 next0, next1, next2, next3);
2655 /* Single loop for potentially the last three packets */
2656 while (n_left_from > 0 && n_left_to_next > 0)
2660 ip6_header_t *ip0 = 0;
2661 ip6_sr_header_t *sr0 = 0;
2663 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2671 n_left_to_next -= 1;
2673 b0 = vlib_get_buffer (vm, bi0);
2675 pool_elt_at_index (sm->sid_lists,
2676 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2677 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2678 vec_len (sl0->rewrite));
2680 ip0 = vlib_buffer_get_current (b0);
2682 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2684 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2685 ip6_ext_header_len (ip0 + 1));
2687 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2689 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2690 (void *) sr0 - (void *) ip0);
2691 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
2692 sl0->rewrite, vec_len (sl0->rewrite));
2694 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2696 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2697 ip0->hop_limit -= 1;
2699 clib_net_to_host_u16 (ip0->payload_length) +
2700 vec_len (sl0->rewrite);
2701 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2703 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2704 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2705 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2707 ip0->dst_address.as_u64[0] =
2708 (sr0->segments + sr0->segments_left)->as_u64[0];
2709 ip0->dst_address.as_u64[1] =
2710 (sr0->segments + sr0->segments_left)->as_u64[1];
2712 if (ip0 + 1 == (void *) sr0)
2714 sr0->protocol = ip0->protocol;
2715 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2719 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2720 sr0->protocol = ip_ext->next_hdr;
2721 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2724 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2725 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2727 sr_policy_rewrite_trace_t *tr =
2728 vlib_add_trace (vm, node, b0, sizeof (*tr));
2729 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
2730 sizeof (tr->src.as_u8));
2731 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
2732 sizeof (tr->dst.as_u8));
2737 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2738 n_left_to_next, bi0, next0);
2741 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2744 /* Update counters */
2745 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2746 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2748 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2749 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2751 return from_frame->n_vectors;
2755 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2756 .function = sr_policy_rewrite_insert,
2757 .name = "sr-pl-rewrite-insert",
2758 .vector_size = sizeof (u32),
2759 .format_trace = format_sr_policy_rewrite_trace,
2760 .type = VLIB_NODE_TYPE_INTERNAL,
2761 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2762 .error_strings = sr_policy_rewrite_error_strings,
2763 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2765 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2766 foreach_sr_policy_rewrite_next
2773 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2776 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2777 vlib_frame_t * from_frame)
2779 ip6_sr_main_t *sm = &sr_main;
2780 u32 n_left_from, next_index, *from, *to_next;
2782 from = vlib_frame_vector_args (from_frame);
2783 n_left_from = from_frame->n_vectors;
2785 next_index = node->cached_next_index;
2787 int insert_pkts = 0, bsid_pkts = 0;
2789 while (n_left_from > 0)
2793 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2796 while (n_left_from >= 8 && n_left_to_next >= 4)
2798 u32 bi0, bi1, bi2, bi3;
2799 vlib_buffer_t *b0, *b1, *b2, *b3;
2800 u32 next0, next1, next2, next3;
2801 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2802 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2803 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2804 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2805 u16 new_l0, new_l1, new_l2, new_l3;
2807 /* Prefetch next iteration. */
2809 vlib_buffer_t *p4, *p5, *p6, *p7;
2811 p4 = vlib_get_buffer (vm, from[4]);
2812 p5 = vlib_get_buffer (vm, from[5]);
2813 p6 = vlib_get_buffer (vm, from[6]);
2814 p7 = vlib_get_buffer (vm, from[7]);
2816 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2817 vlib_prefetch_buffer_header (p4, LOAD);
2818 vlib_prefetch_buffer_header (p5, LOAD);
2819 vlib_prefetch_buffer_header (p6, LOAD);
2820 vlib_prefetch_buffer_header (p7, LOAD);
2822 clib_prefetch_store (p4->data);
2823 clib_prefetch_store (p5->data);
2824 clib_prefetch_store (p6->data);
2825 clib_prefetch_store (p7->data);
2828 to_next[0] = bi0 = from[0];
2829 to_next[1] = bi1 = from[1];
2830 to_next[2] = bi2 = from[2];
2831 to_next[3] = bi3 = from[3];
2835 n_left_to_next -= 4;
2837 b0 = vlib_get_buffer (vm, bi0);
2838 b1 = vlib_get_buffer (vm, bi1);
2839 b2 = vlib_get_buffer (vm, bi2);
2840 b3 = vlib_get_buffer (vm, bi3);
2843 pool_elt_at_index (sm->sid_lists,
2844 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2846 pool_elt_at_index (sm->sid_lists,
2847 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2849 pool_elt_at_index (sm->sid_lists,
2850 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2852 pool_elt_at_index (sm->sid_lists,
2853 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2854 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2855 vec_len (sl0->rewrite_bsid));
2856 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2857 vec_len (sl1->rewrite_bsid));
2858 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2859 vec_len (sl2->rewrite_bsid));
2860 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2861 vec_len (sl3->rewrite_bsid));
2863 ip0 = vlib_buffer_get_current (b0);
2864 ip1 = vlib_buffer_get_current (b1);
2865 ip2 = vlib_buffer_get_current (b2);
2866 ip3 = vlib_buffer_get_current (b3);
2868 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2870 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2871 ip6_ext_header_len (ip0 + 1));
2873 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2875 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2877 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2878 ip6_ext_header_len (ip1 + 1));
2880 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2882 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2884 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2885 ip6_ext_header_len (ip2 + 1));
2887 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2889 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2891 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2892 ip6_ext_header_len (ip3 + 1));
2894 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2896 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
2897 (u8 *) ip0, (void *) sr0 - (void *) ip0);
2898 clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
2899 (u8 *) ip1, (void *) sr1 - (void *) ip1);
2900 clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
2901 (u8 *) ip2, (void *) sr2 - (void *) ip2);
2902 clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
2903 (u8 *) ip3, (void *) sr3 - (void *) ip3);
2905 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2906 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2907 clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2908 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2909 clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2910 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2911 clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2912 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2914 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2915 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2916 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2917 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2919 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2920 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2921 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2922 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2924 ip0->hop_limit -= 1;
2925 ip1->hop_limit -= 1;
2926 ip2->hop_limit -= 1;
2927 ip3->hop_limit -= 1;
2930 clib_net_to_host_u16 (ip0->payload_length) +
2931 vec_len (sl0->rewrite_bsid);
2933 clib_net_to_host_u16 (ip1->payload_length) +
2934 vec_len (sl1->rewrite_bsid);
2936 clib_net_to_host_u16 (ip2->payload_length) +
2937 vec_len (sl2->rewrite_bsid);
2939 clib_net_to_host_u16 (ip3->payload_length) +
2940 vec_len (sl3->rewrite_bsid);
2942 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2943 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2944 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2945 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2947 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2948 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2949 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2950 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2952 ip0->dst_address.as_u64[0] =
2953 (sr0->segments + sr0->segments_left)->as_u64[0];
2954 ip0->dst_address.as_u64[1] =
2955 (sr0->segments + sr0->segments_left)->as_u64[1];
2956 ip1->dst_address.as_u64[0] =
2957 (sr1->segments + sr1->segments_left)->as_u64[0];
2958 ip1->dst_address.as_u64[1] =
2959 (sr1->segments + sr1->segments_left)->as_u64[1];
2960 ip2->dst_address.as_u64[0] =
2961 (sr2->segments + sr2->segments_left)->as_u64[0];
2962 ip2->dst_address.as_u64[1] =
2963 (sr2->segments + sr2->segments_left)->as_u64[1];
2964 ip3->dst_address.as_u64[0] =
2965 (sr3->segments + sr3->segments_left)->as_u64[0];
2966 ip3->dst_address.as_u64[1] =
2967 (sr3->segments + sr3->segments_left)->as_u64[1];
2969 ip6_ext_header_t *ip_ext;
2970 if (ip0 + 1 == (void *) sr0)
2972 sr0->protocol = ip0->protocol;
2973 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2977 ip_ext = (void *) (ip0 + 1);
2978 sr0->protocol = ip_ext->next_hdr;
2979 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2982 if (ip1 + 1 == (void *) sr1)
2984 sr1->protocol = ip1->protocol;
2985 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2989 ip_ext = (void *) (ip2 + 1);
2990 sr2->protocol = ip_ext->next_hdr;
2991 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2994 if (ip2 + 1 == (void *) sr2)
2996 sr2->protocol = ip2->protocol;
2997 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
3001 ip_ext = (void *) (ip2 + 1);
3002 sr2->protocol = ip_ext->next_hdr;
3003 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3006 if (ip3 + 1 == (void *) sr3)
3008 sr3->protocol = ip3->protocol;
3009 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
3013 ip_ext = (void *) (ip3 + 1);
3014 sr3->protocol = ip_ext->next_hdr;
3015 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3020 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3022 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3024 sr_policy_rewrite_trace_t *tr =
3025 vlib_add_trace (vm, node, b0, sizeof (*tr));
3026 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3027 sizeof (tr->src.as_u8));
3028 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3029 sizeof (tr->dst.as_u8));
3032 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3034 sr_policy_rewrite_trace_t *tr =
3035 vlib_add_trace (vm, node, b1, sizeof (*tr));
3036 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3037 sizeof (tr->src.as_u8));
3038 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3039 sizeof (tr->dst.as_u8));
3042 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3044 sr_policy_rewrite_trace_t *tr =
3045 vlib_add_trace (vm, node, b2, sizeof (*tr));
3046 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3047 sizeof (tr->src.as_u8));
3048 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3049 sizeof (tr->dst.as_u8));
3052 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3054 sr_policy_rewrite_trace_t *tr =
3055 vlib_add_trace (vm, node, b3, sizeof (*tr));
3056 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3057 sizeof (tr->src.as_u8));
3058 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3059 sizeof (tr->dst.as_u8));
3063 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3064 n_left_to_next, bi0, bi1, bi2, bi3,
3065 next0, next1, next2, next3);
3068 /* Single loop for potentially the last three packets */
3069 while (n_left_from > 0 && n_left_to_next > 0)
3073 ip6_header_t *ip0 = 0;
3074 ip6_sr_header_t *sr0 = 0;
3076 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3084 n_left_to_next -= 1;
3086 b0 = vlib_get_buffer (vm, bi0);
3088 pool_elt_at_index (sm->sid_lists,
3089 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3090 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3091 vec_len (sl0->rewrite_bsid));
3093 ip0 = vlib_buffer_get_current (b0);
3095 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
3097 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
3098 ip6_ext_header_len (ip0 + 1));
3100 sr0 = (ip6_sr_header_t *) (ip0 + 1);
3102 clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
3103 (u8 *) ip0, (void *) sr0 - (void *) ip0);
3104 clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
3105 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
3107 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
3109 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
3110 ip0->hop_limit -= 1;
3112 clib_net_to_host_u16 (ip0->payload_length) +
3113 vec_len (sl0->rewrite_bsid);
3114 ip0->payload_length = clib_host_to_net_u16 (new_l0);
3116 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
3118 ip0->dst_address.as_u64[0] =
3119 (sr0->segments + sr0->segments_left)->as_u64[0];
3120 ip0->dst_address.as_u64[1] =
3121 (sr0->segments + sr0->segments_left)->as_u64[1];
3123 if (ip0 + 1 == (void *) sr0)
3125 sr0->protocol = ip0->protocol;
3126 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
3130 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
3131 sr0->protocol = ip_ext->next_hdr;
3132 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
3135 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3136 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3138 sr_policy_rewrite_trace_t *tr =
3139 vlib_add_trace (vm, node, b0, sizeof (*tr));
3140 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3141 sizeof (tr->src.as_u8));
3142 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3143 sizeof (tr->dst.as_u8));
3148 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3149 n_left_to_next, bi0, next0);
3152 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3155 /* Update counters */
3156 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3157 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3159 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
3160 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3162 return from_frame->n_vectors;
3166 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
3167 .function = sr_policy_rewrite_b_insert,
3168 .name = "sr-pl-rewrite-b-insert",
3169 .vector_size = sizeof (u32),
3170 .format_trace = format_sr_policy_rewrite_trace,
3171 .type = VLIB_NODE_TYPE_INTERNAL,
3172 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3173 .error_strings = sr_policy_rewrite_error_strings,
3174 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3176 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3177 foreach_sr_policy_rewrite_next
3184 * @brief Function BSID encapsulation
3186 static_always_inline void
3187 end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
3188 ip6_header_t *ip0, ip6_sr_header_t *sr0,
3189 u32 *next0, u8 policy_type)
3191 ip6_address_t *new_dst0;
3193 if (PREDICT_FALSE (!sr0))
3194 goto error_bsid_encaps;
3196 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
3198 if (PREDICT_TRUE (sr0->segments_left != 0))
3200 sr0->segments_left -= 1;
3201 new_dst0 = (ip6_address_t *) (sr0->segments);
3202 new_dst0 += sr0->segments_left;
3203 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
3204 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
3207 else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
3212 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
3213 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
3217 * @brief Graph node for applying a SR policy BSID - Encapsulation
3220 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
3221 vlib_frame_t * from_frame)
3223 ip6_sr_main_t *sm = &sr_main;
3224 u32 n_left_from, next_index, *from, *to_next;
3226 from = vlib_frame_vector_args (from_frame);
3227 n_left_from = from_frame->n_vectors;
3229 next_index = node->cached_next_index;
3231 int encap_pkts = 0, bsid_pkts = 0;
3233 while (n_left_from > 0)
3237 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3240 while (n_left_from >= 8 && n_left_to_next >= 4)
3242 u32 bi0, bi1, bi2, bi3;
3243 vlib_buffer_t *b0, *b1, *b2, *b3;
3244 u32 next0, next1, next2, next3;
3245 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3246 ip6_header_t *ip0, *ip1, *ip2, *ip3;
3247 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
3248 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
3249 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
3251 /* Prefetch next iteration. */
3253 vlib_buffer_t *p4, *p5, *p6, *p7;
3255 p4 = vlib_get_buffer (vm, from[4]);
3256 p5 = vlib_get_buffer (vm, from[5]);
3257 p6 = vlib_get_buffer (vm, from[6]);
3258 p7 = vlib_get_buffer (vm, from[7]);
3260 /* Prefetch the buffer header and packet for the N+2 loop iteration */
3261 vlib_prefetch_buffer_header (p4, LOAD);
3262 vlib_prefetch_buffer_header (p5, LOAD);
3263 vlib_prefetch_buffer_header (p6, LOAD);
3264 vlib_prefetch_buffer_header (p7, LOAD);
3266 clib_prefetch_store (p4->data);
3267 clib_prefetch_store (p5->data);
3268 clib_prefetch_store (p6->data);
3269 clib_prefetch_store (p7->data);
3272 to_next[0] = bi0 = from[0];
3273 to_next[1] = bi1 = from[1];
3274 to_next[2] = bi2 = from[2];
3275 to_next[3] = bi3 = from[3];
3279 n_left_to_next -= 4;
3281 b0 = vlib_get_buffer (vm, bi0);
3282 b1 = vlib_get_buffer (vm, bi1);
3283 b2 = vlib_get_buffer (vm, bi2);
3284 b3 = vlib_get_buffer (vm, bi3);
3287 pool_elt_at_index (sm->sid_lists,
3288 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3290 pool_elt_at_index (sm->sid_lists,
3291 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
3293 pool_elt_at_index (sm->sid_lists,
3294 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
3296 pool_elt_at_index (sm->sid_lists,
3297 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
3298 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3299 vec_len (sl0->rewrite));
3300 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3301 vec_len (sl1->rewrite));
3302 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3303 vec_len (sl2->rewrite));
3304 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3305 vec_len (sl3->rewrite));
3307 ip0_encap = vlib_buffer_get_current (b0);
3308 ip1_encap = vlib_buffer_get_current (b1);
3309 ip2_encap = vlib_buffer_get_current (b2);
3310 ip3_encap = vlib_buffer_get_current (b3);
3313 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3316 ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
3319 ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
3322 ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
3325 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3327 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
3329 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
3331 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
3334 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3335 sl0->rewrite, vec_len (sl0->rewrite));
3336 clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3337 sl1->rewrite, vec_len (sl1->rewrite));
3338 clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3339 sl2->rewrite, vec_len (sl2->rewrite));
3340 clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3341 sl3->rewrite, vec_len (sl3->rewrite));
3343 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3344 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3345 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3346 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3348 ip0 = vlib_buffer_get_current (b0);
3349 ip1 = vlib_buffer_get_current (b1);
3350 ip2 = vlib_buffer_get_current (b2);
3351 ip3 = vlib_buffer_get_current (b3);
3353 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3354 encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
3355 encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
3356 encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
3358 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3360 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3362 sr_policy_rewrite_trace_t *tr =
3363 vlib_add_trace (vm, node, b0, sizeof (*tr));
3364 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3365 sizeof (tr->src.as_u8));
3366 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3367 sizeof (tr->dst.as_u8));
3370 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3372 sr_policy_rewrite_trace_t *tr =
3373 vlib_add_trace (vm, node, b1, sizeof (*tr));
3374 clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
3375 sizeof (tr->src.as_u8));
3376 clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
3377 sizeof (tr->dst.as_u8));
3380 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3382 sr_policy_rewrite_trace_t *tr =
3383 vlib_add_trace (vm, node, b2, sizeof (*tr));
3384 clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
3385 sizeof (tr->src.as_u8));
3386 clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
3387 sizeof (tr->dst.as_u8));
3390 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3392 sr_policy_rewrite_trace_t *tr =
3393 vlib_add_trace (vm, node, b3, sizeof (*tr));
3394 clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
3395 sizeof (tr->src.as_u8));
3396 clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
3397 sizeof (tr->dst.as_u8));
3402 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3403 n_left_to_next, bi0, bi1, bi2, bi3,
3404 next0, next1, next2, next3);
3407 /* Single loop for potentially the last three packets */
3408 while (n_left_from > 0 && n_left_to_next > 0)
3412 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3413 ip6_sr_header_t *sr0;
3415 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3422 n_left_to_next -= 1;
3423 b0 = vlib_get_buffer (vm, bi0);
3426 pool_elt_at_index (sm->sid_lists,
3427 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3428 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3429 vec_len (sl0->rewrite));
3431 ip0_encap = vlib_buffer_get_current (b0);
3433 ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
3435 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
3438 clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3439 sl0->rewrite, vec_len (sl0->rewrite));
3440 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3442 ip0 = vlib_buffer_get_current (b0);
3444 encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
3446 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3447 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3449 sr_policy_rewrite_trace_t *tr =
3450 vlib_add_trace (vm, node, b0, sizeof (*tr));
3451 clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
3452 sizeof (tr->src.as_u8));
3453 clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
3454 sizeof (tr->dst.as_u8));
3458 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3459 n_left_to_next, bi0, next0);
3462 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3465 /* Update counters */
3466 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3467 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3469 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3470 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3473 return from_frame->n_vectors;
3477 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3478 .function = sr_policy_rewrite_b_encaps,
3479 .name = "sr-pl-rewrite-b-encaps",
3480 .vector_size = sizeof (u32),
3481 .format_trace = format_sr_policy_rewrite_trace,
3482 .type = VLIB_NODE_TYPE_INTERNAL,
3483 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3484 .error_strings = sr_policy_rewrite_error_strings,
3485 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3487 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3488 foreach_sr_policy_rewrite_next
3494 /*************************** SR Policy plugins ******************************/
3496 * @brief SR Policy plugin registry
3499 sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
3500 u8 * keyword_str, u8 * def_str,
3501 u8 * params_str, u8 prefix_length,
3503 format_function_t * ls_format,
3504 unformat_function_t * ls_unformat,
3505 sr_p_plugin_callback_t * creation_fn,
3506 sr_p_plugin_callback_t * removal_fn)
3508 ip6_sr_main_t *sm = &sr_main;
3511 sr_policy_fn_registration_t *plugin;
3513 /* Did this function exist? If so update it */
3514 p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
3517 plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
3519 /* Else create a new one and set hash key */
3522 pool_get (sm->policy_plugin_functions, plugin);
3523 hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
3524 plugin - sm->policy_plugin_functions);
3527 clib_memset (plugin, 0, sizeof (*plugin));
3529 plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
3530 plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
3531 plugin->prefix_length = prefix_length;
3532 plugin->ls_format = ls_format;
3533 plugin->ls_unformat = ls_unformat;
3534 plugin->creation = creation_fn;
3535 plugin->removal = removal_fn;
3536 clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
3537 plugin->function_name = format (0, "%s%c", fn_name, 0);
3538 plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
3539 plugin->def_str = format (0, "%s%c", def_str, 0);
3540 plugin->params_str = format (0, "%s%c", params_str, 0);
3542 return plugin->sr_policy_function_number;
3546 * @brief CLI function to 'show' all available SR LocalSID behaviors
3548 static clib_error_t *
3549 show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
3550 unformat_input_t * input,
3551 vlib_cli_command_t * cmd)
3553 ip6_sr_main_t *sm = &sr_main;
3554 sr_policy_fn_registration_t *plugin;
3555 sr_policy_fn_registration_t **plugins_vec = 0;
3558 vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
3561 pool_foreach (plugin, sm->policy_plugin_functions)
3562 { vec_add1 (plugins_vec, plugin); }
3565 vlib_cli_output (vm, "Plugin behaviors:\n");
3566 for (i = 0; i < vec_len (plugins_vec); i++)
3568 plugin = plugins_vec[i];
3569 vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
3571 vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
3577 VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
3578 .path = "show sr policy behaviors",
3579 .short_help = "show sr policy behaviors",
3580 .function = show_sr_policy_behaviors_command_fn,
3584 /*************************** SR Segment Lists DPOs ****************************/
3586 format_sr_segment_list_dpo (u8 * s, va_list * args)
3588 ip6_sr_main_t *sm = &sr_main;
3589 ip6_address_t *addr;
3592 index_t index = va_arg (*args, index_t);
3593 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3594 s = format (s, "SR: Segment List index:[%d]", index);
3595 s = format (s, "\n\tSegments:");
3597 sl = pool_elt_at_index (sm->sid_lists, index);
3599 s = format (s, "< ");
3600 vec_foreach (addr, sl->segments)
3602 s = format (s, "%U, ", format_ip6_address, addr);
3604 s = format (s, "\b\b > - ");
3605 s = format (s, "Weight: %u", sl->weight);
3610 const static dpo_vft_t sr_policy_rewrite_vft = {
3611 .dv_lock = sr_dpo_lock,
3612 .dv_unlock = sr_dpo_unlock,
3613 .dv_format = format_sr_segment_list_dpo,
3616 const static char *const sr_pr_encaps_ip6_nodes[] = {
3617 "sr-pl-rewrite-encaps",
3621 const static char *const sr_pr_encaps_ip4_nodes[] = {
3622 "sr-pl-rewrite-encaps-v4",
3626 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3627 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3628 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3631 const static char *const sr_pr_insert_ip6_nodes[] = {
3632 "sr-pl-rewrite-insert",
3636 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3637 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3640 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3641 "sr-pl-rewrite-b-insert",
3645 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3646 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3649 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3650 "sr-pl-rewrite-b-encaps",
3654 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3655 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3658 /********************* SR Policy Rewrite initialization ***********************/
3660 * @brief SR Policy Rewrite initialization
3663 sr_policy_rewrite_init (vlib_main_t * vm)
3665 ip6_sr_main_t *sm = &sr_main;
3667 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3668 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3669 sizeof (ip6_address_t));
3671 /* Init SR VPO DPOs type */
3672 sr_pr_encaps_dpo_type =
3673 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3675 sr_pr_insert_dpo_type =
3676 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3678 sr_pr_bsid_encaps_dpo_type =
3679 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3681 sr_pr_bsid_insert_dpo_type =
3682 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3684 /* Register the L2 encaps node used in HW redirect */
3685 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3687 sm->fib_table_ip6 = (u32) ~ 0;
3688 sm->fib_table_ip4 = (u32) ~ 0;
3693 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3697 * fd.io coding-style-patch-verification: ON
3700 * eval: (c-set-style "gnu")