2 * sr_policy_rewrite.c: ipv6 sr policy creation
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief SR policy creation and application
22 * Create an SR policy.
23 * An SR policy can be either of 'default' type or 'spray' type
24 * An SR policy has attached a list of SID lists.
25 * In case the SR policy is a default one it will load balance among them.
26 * An SR policy has associated a BindingSID.
27 * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28 * associated to such bindingSID will be applied to such packet.
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
33 * Traffic input usually is IPv6 packets. However it is possible to have
34 * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
36 * This file provides the appropiates VPP graph nodes to do any of these
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/sr/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/sr/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
55 * @brief SR policy rewrite trace
59 ip6_address_t src, dst;
60 } sr_policy_rewrite_trace_t;
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
72 SR_POLICY_REWRITE_N_NEXT,
73 } sr_policy_rewrite_next_t;
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
89 SR_POLICY_REWRITE_N_ERROR,
90 } sr_policy_rewrite_error_t;
92 static char *sr_policy_rewrite_error_strings[] = {
93 #define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
99 * @brief Dynamically added SR SL DPO type
101 static dpo_type_t sr_pr_encaps_dpo_type;
102 static dpo_type_t sr_pr_insert_dpo_type;
103 static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104 static dpo_type_t sr_pr_bsid_insert_dpo_type;
107 * @brief IPv6 SA for encapsulated packets
109 static ip6_address_t sr_pr_encaps_src;
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113 take the ip address of a loopback interface or even the OIF */
115 static clib_error_t *
116 set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
125 return clib_error_return (0, "No address specified");
127 return clib_error_return (0, "No address specified");
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132 .path = "set sr encaps source",
133 .short_help = "set sr encaps source addr <ip6_addr>",
134 .function = set_sr_src_command_fn,
138 /*********************** SR rewrite string computation ************************/
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
142 * @param sl is a vector of IPv6 addresses composing the Segment List
144 * @return precomputed rewrite string for encapsulation
147 compute_rewrite_encaps (ip6_address_t * sl)
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
163 vec_validate (rs, header_length - 1);
165 iph = (ip6_header_t *) rs;
166 iph->ip_version_traffic_class_and_flow_label =
167 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168 iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169 iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170 iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171 iph->protocol = IP_PROTOCOL_IPV6;
172 iph->hop_limit = IPv6_DEFAULT_HOP_LIMIT;
174 srh = (ip6_sr_header_t *) (iph + 1);
175 iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176 srh->protocol = IP_PROTOCOL_IPV6;
177 srh->type = ROUTING_HEADER_TYPE_SR;
178 srh->segments_left = vec_len (sl) - 1;
179 srh->first_segment = vec_len (sl) - 1;
180 srh->length = ((sizeof (ip6_sr_header_t) +
181 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
196 * @brief SR rewrite string computation for SRH insertion (inline)
198 * @param sl is a vector of IPv6 addresses composing the Segment List
200 * @return precomputed rewrite string for SRH insertion
203 compute_rewrite_insert (ip6_address_t * sl)
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
214 vec_validate (rs, header_length - 1);
216 srh = (ip6_sr_header_t *) rs;
217 srh->type = ROUTING_HEADER_TYPE_SR;
218 srh->segments_left = vec_len (sl);
219 srh->first_segment = vec_len (sl);
220 srh->length = ((sizeof (ip6_sr_header_t) +
221 ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
236 * @param sl is a vector of IPv6 addresses composing the Segment List
238 * @return precomputed rewrite string for SRH insertion with BSID
241 compute_rewrite_bsid (ip6_address_t * sl)
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
252 vec_validate (rs, header_length - 1);
254 srh = (ip6_sr_header_t *) rs;
255 srh->type = ROUTING_HEADER_TYPE_SR;
256 srh->segments_left = vec_len (sl) - 1;
257 srh->first_segment = vec_len (sl) - 1;
258 srh->length = ((sizeof (ip6_sr_header_t) +
259 (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
271 /*************************** SR LB helper functions **************************/
273 * @brief Creates a Segment List and adds it to an SR policy
275 * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276 * not necessarily unique. Hence there might be two Segment List within the
277 * same SR Policy with exactly the same segments and same weight.
279 * @param sr_policy is the SR policy where the SL will be added
280 * @param sl is a vector of IPv6 addresses composing the Segment List
281 * @param weight is the weight of the SegmentList (for load-balancing purposes)
282 * @param is_encap represents the mode (SRH insertion vs Encapsulation)
284 * @return pointer to the just created segment list
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
298 /* Fill in segment list */
299 segment_list->weight =
300 (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301 segment_list->segments = vec_dup (sl);
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
321 dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP6,
322 segment_list - sm->sid_lists);
323 dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type, DPO_PROTO_IP4,
324 segment_list - sm->sid_lists);
325 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
326 DPO_PROTO_IP6, segment_list - sm->sid_lists);
330 dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type, DPO_PROTO_IP6,
331 segment_list - sm->sid_lists);
332 dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
333 DPO_PROTO_IP6, segment_list - sm->sid_lists);
340 * @brief Updates the Load Balancer after an SR Policy change
342 * @param sr_policy is the modified SR Policy
345 update_lb (ip6_sr_policy_t * sr_policy)
347 flow_hash_config_t fhc;
349 ip6_sr_sl_t *segment_list;
350 ip6_sr_main_t *sm = &sr_main;
351 load_balance_path_t path;
352 load_balance_path_t *ip4_path_vector = 0;
353 load_balance_path_t *ip6_path_vector = 0;
354 load_balance_path_t *b_path_vector = 0;
356 /* In case LB does not exist, create it */
357 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
360 .fp_proto = FIB_PROTOCOL_IP6,
363 .ip6 = sr_policy->bsid,
367 /* Add FIB entry for BSID */
368 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
369 dpo_proto_to_fib (DPO_PROTO_IP6));
371 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
372 load_balance_create (0, DPO_PROTO_IP6, fhc));
374 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
375 load_balance_create (0, DPO_PROTO_IP6, fhc));
377 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
378 fib_table_entry_special_dpo_update (fib_table_id_find_fib_index
380 sr_policy->fib_table), &pfx,
382 FIB_ENTRY_FLAG_EXCLUSIVE,
383 &sr_policy->bsid_dpo);
385 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->ip6_dpo);
391 if (sr_policy->is_encap)
393 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
394 load_balance_create (0, DPO_PROTO_IP4, fhc));
396 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
399 FIB_ENTRY_FLAG_EXCLUSIVE,
400 &sr_policy->ip4_dpo);
405 /* Create the LB path vector */
406 //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
407 vec_foreach (sl_index, sr_policy->segments_lists)
409 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
410 path.path_dpo = segment_list->bsid_dpo;
411 path.path_weight = segment_list->weight;
412 vec_add1 (b_path_vector, path);
413 path.path_dpo = segment_list->ip6_dpo;
414 vec_add1 (ip6_path_vector, path);
415 if (sr_policy->is_encap)
417 path.path_dpo = segment_list->ip4_dpo;
418 vec_add1 (ip4_path_vector, path);
422 /* Update LB multipath */
423 load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
424 LOAD_BALANCE_FLAG_NONE);
425 load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
426 LOAD_BALANCE_FLAG_NONE);
427 if (sr_policy->is_encap)
428 load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
429 LOAD_BALANCE_FLAG_NONE);
432 vec_free (b_path_vector);
433 vec_free (ip6_path_vector);
434 vec_free (ip4_path_vector);
439 * @brief Updates the Replicate DPO after an SR Policy change
441 * @param sr_policy is the modified SR Policy (type spray)
444 update_replicate (ip6_sr_policy_t * sr_policy)
447 ip6_sr_sl_t *segment_list;
448 ip6_sr_main_t *sm = &sr_main;
449 load_balance_path_t path;
450 load_balance_path_t *b_path_vector = 0;
451 load_balance_path_t *ip6_path_vector = 0;
452 load_balance_path_t *ip4_path_vector = 0;
454 /* In case LB does not exist, create it */
455 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
457 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
458 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
460 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
461 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
463 /* Update FIB entry's DPO to point to SR without LB */
465 .fp_proto = FIB_PROTOCOL_IP6,
468 .ip6 = sr_policy->bsid,
471 fib_table_entry_special_dpo_update (fib_table_id_find_fib_index
473 sr_policy->fib_table), &pfx,
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
484 if (sr_policy->is_encap)
486 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
487 replicate_create (0, DPO_PROTO_IP4));
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
498 /* Create the replicate path vector */
499 path.path_weight = 1;
500 vec_foreach (sl_index, sr_policy->segments_lists)
502 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
503 path.path_dpo = segment_list->bsid_dpo;
504 vec_add1 (b_path_vector, path);
505 path.path_dpo = segment_list->ip6_dpo;
506 vec_add1 (ip6_path_vector, path);
507 if (sr_policy->is_encap)
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
514 /* Update replicate multipath */
515 replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
516 replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
517 if (sr_policy->is_encap)
518 replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
521 vec_free (b_path_vector);
522 vec_free (ip6_path_vector);
523 vec_free (ip4_path_vector);
526 /******************************* SR rewrite API *******************************/
527 /* Three functions for handling sr policies:
531 * All of them are API. CLI function on sr_policy_command_fn */
534 * @brief Create a new SR policy
536 * @param bsid is the bindingSID of the SR Policy
537 * @param segments is a vector of IPv6 address composing the segment list
538 * @param weight is the weight of the sid list. optional.
539 * @param behavior is the behavior of the SR policy. (default//spray)
540 * @param fib_table is the VRF where to install the FIB entry for the BSID
541 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
543 * @return 0 if correct, else error
546 sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
547 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
549 ip6_sr_main_t *sm = &sr_main;
550 ip6_sr_policy_t *sr_policy = 0;
551 ip6_address_t *key_copy;
554 /* Search for existing keys (BSID) */
555 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
558 /* Add SR policy that already exists; complain */
562 /* Search collision in FIB entries */
563 /* Explanation: It might be possible that some other entity has already
564 * created a route for the BSID. This in theory is impossible, but in
565 * practise we could see it. Assert it and scream if needed */
567 .fp_proto = FIB_PROTOCOL_IP6,
574 /* Lookup the FIB index associated to the table selected */
575 u32 fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6,
577 (u32) ~ 0 ? fib_table : 0));
581 /* Lookup whether there exists an entry for the BSID */
582 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
583 if (FIB_NODE_INDEX_INVALID != fei)
584 return -12; //There is an entry for such lookup
586 /* Add an SR policy object */
587 pool_get (sm->sr_policies, sr_policy);
588 memset (sr_policy, 0, sizeof (*sr_policy));
589 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
590 sr_policy->type = behavior;
591 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
592 sr_policy->is_encap = is_encap;
595 key_copy = vec_new (ip6_address_t, 1);
596 clib_memcpy (key_copy, bsid, sizeof (ip6_address_t));
597 hash_set_mem (sm->sr_policy_index_by_key, key_copy,
598 sr_policy - sm->sr_policies);
600 /* Create a segment list and add the index to the SR policy */
601 create_sl (sr_policy, segments, weight, is_encap);
603 /* If FIB doesnt exist, create them */
604 if (sm->fib_table_ip6 == (u32) ~ 0)
606 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
607 "SRv6 steering of IP6 prefixes through BSIDs");
608 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
609 "SRv6 steering of IP4 prefixes through BSIDs");
610 fib_table_flush (sm->fib_table_ip6, FIB_PROTOCOL_IP6,
612 fib_table_flush (sm->fib_table_ip4, FIB_PROTOCOL_IP6,
616 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
617 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
618 update_lb (sr_policy);
619 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
620 update_replicate (sr_policy);
625 * @brief Delete a SR policy
627 * @param bsid is the bindingSID of the SR Policy
628 * @param index is the index of the SR policy
630 * @return 0 if correct, else error
633 sr_policy_del (ip6_address_t * bsid, u32 index)
635 ip6_sr_main_t *sm = &sr_main;
636 ip6_sr_policy_t *sr_policy = 0;
637 ip6_sr_sl_t *segment_list;
638 ip6_address_t *key_copy;
645 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
647 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
653 sr_policy = pool_elt_at_index (sm->sr_policies, index);
658 /* Remove BindingSID FIB entry */
660 .fp_proto = FIB_PROTOCOL_IP6,
663 .ip6 = sr_policy->bsid,
668 fib_table_entry_special_remove (fib_table_id_find_fib_index
669 (FIB_PROTOCOL_IP6, sr_policy->fib_table),
670 &pfx, FIB_SOURCE_SR);
672 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
674 if (sr_policy->is_encap)
675 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
677 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
679 dpo_reset (&sr_policy->bsid_dpo);
680 dpo_reset (&sr_policy->ip4_dpo);
681 dpo_reset (&sr_policy->ip6_dpo);
684 /* Clean SID Lists */
685 vec_foreach (sl_index, sr_policy->segments_lists)
687 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
688 vec_free (segment_list->segments);
689 vec_free (segment_list->rewrite);
690 vec_free (segment_list->rewrite_bsid);
691 pool_put_index (sm->sid_lists, *sl_index);
694 /* Remove SR policy entry */
695 hp = hash_get_pair (sm->sr_policy_index_by_key, &sr_policy->bsid);
696 key_copy = (void *) (hp->key);
697 hash_unset_mem (sm->sr_policy_index_by_key, &sr_policy->bsid);
699 pool_put (sm->sr_policies, sr_policy);
701 /* If FIB empty unlock it */
702 if (!pool_elts (sm->sr_policies))
704 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6);
705 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6);
706 sm->fib_table_ip6 = (u32) ~ 0;
707 sm->fib_table_ip4 = (u32) ~ 0;
714 * @brief Modify an existing SR policy
716 * The possible modifications are adding a new Segment List, modifying an
717 * existing Segment List (modify the weight only) and delete a given
718 * Segment List from the SR Policy.
720 * @param bsid is the bindingSID of the SR Policy
721 * @param index is the index of the SR policy
722 * @param fib_table is the VRF where to install the FIB entry for the BSID
723 * @param operation is the operation to perform (among the top ones)
724 * @param segments is a vector of IPv6 address composing the segment list
725 * @param sl_index is the index of the Segment List to modify/delete
726 * @param weight is the weight of the sid list. optional.
727 * @param is_encap Mode. Encapsulation or SRH insertion.
729 * @return 0 if correct, else error
732 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
733 u8 operation, ip6_address_t * segments, u32 sl_index,
736 ip6_sr_main_t *sm = &sr_main;
737 ip6_sr_policy_t *sr_policy = 0;
738 ip6_sr_sl_t *segment_list;
739 u32 *sl_index_iterate;
744 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
746 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
752 sr_policy = pool_elt_at_index (sm->sr_policies, index);
757 if (operation == 1) /* Add SR List to an existing SR policy */
759 /* Create the new SL */
761 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
763 /* Create a new LB DPO */
764 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
765 update_lb (sr_policy);
766 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
767 update_replicate (sr_policy);
769 else if (operation == 2) /* Delete SR List from an existing SR policy */
771 /* Check that currently there are more than one SID list */
772 if (vec_len (sr_policy->segments_lists) == 1)
775 /* Check that the SR list does exist and is assigned to the sr policy */
776 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
777 if (*sl_index_iterate == sl_index)
780 if (*sl_index_iterate != sl_index)
783 /* Remove the lucky SR list that is being kicked out */
784 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
785 vec_free (segment_list->segments);
786 vec_free (segment_list->rewrite);
787 vec_free (segment_list->rewrite_bsid);
788 pool_put_index (sm->sid_lists, sl_index);
789 vec_del1 (sr_policy->segments_lists,
790 sl_index_iterate - sr_policy->segments_lists);
792 /* Create a new LB DPO */
793 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
794 update_lb (sr_policy);
795 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
796 update_replicate (sr_policy);
798 else if (operation == 3) /* Modify the weight of an existing SR List */
800 /* Find the corresponding SL */
801 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
802 if (*sl_index_iterate == sl_index)
805 if (*sl_index_iterate != sl_index)
808 /* Change the weight */
809 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
810 segment_list->weight = weight;
813 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
814 update_lb (sr_policy);
816 else /* Incorrect op. */
823 * @brief CLI for 'sr policies' command family
825 static clib_error_t *
826 sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
827 vlib_cli_command_t * cmd)
830 char is_del = 0, is_add = 0, is_mod = 0;
832 ip6_address_t bsid, next_address;
833 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
834 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
835 ip6_address_t *segments = 0, *this_seg;
840 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
842 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
844 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
846 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
849 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
851 else if (!is_add && !policy_set
852 && unformat (input, "index %d", &sr_policy_index))
854 else if (unformat (input, "weight %d", &weight));
856 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
858 vec_add2 (segments, this_seg, 1);
859 clib_memcpy (this_seg->as_u8, next_address.as_u8,
862 else if (unformat (input, "add sl"))
864 else if (unformat (input, "del sl index %d", &sl_index))
866 else if (unformat (input, "mod sl index %d", &sl_index))
868 else if (fib_table == (u32) ~ 0
869 && unformat (input, "fib-table %d", &fib_table));
870 else if (unformat (input, "encap"))
872 else if (unformat (input, "insert"))
874 else if (unformat (input, "spray"))
880 if (!is_add && !is_mod && !is_del)
881 return clib_error_return (0, "Incorrect CLI");
884 return clib_error_return (0, "No SR policy BSID or index specified");
888 if (vec_len (segments) == 0)
889 return clib_error_return (0, "No Segment List specified");
890 rv = sr_policy_add (&bsid, segments, weight,
891 (is_spray ? SR_POLICY_TYPE_SPRAY :
892 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
895 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
900 return clib_error_return (0, "No SL modification specified");
901 if (operation != 1 && sl_index == (u32) ~ 0)
902 return clib_error_return (0, "No Segment List index specified");
903 if (operation == 1 && vec_len (segments) == 0)
904 return clib_error_return (0, "No Segment List specified");
905 if (operation == 3 && weight == (u32) ~ 0)
906 return clib_error_return (0, "No new weight for the SL specified");
907 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
908 sr_policy_index, fib_table, operation, segments,
919 return clib_error_return (0,
920 "There is already a FIB entry for the BindingSID address.\n"
921 "The SR policy could not be created.");
923 return clib_error_return (0, "The specified FIB table does not exist.");
925 return clib_error_return (0,
926 "The selected SR policy only contains ONE segment list. "
927 "Please remove the SR policy instead");
929 return clib_error_return (0,
930 "Could not delete the segment list. "
931 "It is not associated with that SR policy.");
933 return clib_error_return (0,
934 "Could not modify the segment list. "
935 "The given SL is not associated with such SR policy.");
937 return clib_error_return (0, "BUG: sr policy returns %d", rv);
943 VLIB_CLI_COMMAND (sr_policy_command, static) = {
945 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
946 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
948 "Manipulation of SR policies.\n"
949 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
950 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
951 "Segment Routing policies might be of type encapsulation or srh insertion\n"
952 "Each SR policy will be associated with a unique BindingSID.\n"
953 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
954 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
955 "The add command will create a SR policy with its first segment list (sl)\n"
956 "The mod command allows you to add, remove, or modify the existing segment lists\n"
957 "within an SR policy.\n"
958 "The del command allows you to delete a SR policy along with all its associated\n"
960 .function = sr_policy_command_fn,
965 * @brief CLI to display onscreen all the SR policies
967 static clib_error_t *
968 show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
969 vlib_cli_command_t * cmd)
971 ip6_sr_main_t *sm = &sr_main;
973 ip6_sr_sl_t *segment_list = 0;
974 ip6_sr_policy_t *sr_policy = 0;
975 ip6_sr_policy_t **vec_policies = 0;
980 vlib_cli_output (vm, "SR policies:");
983 pool_foreach (sr_policy, sm->sr_policies,
984 {vec_add1 (vec_policies, sr_policy); } );
987 vec_foreach_index (i, vec_policies)
989 sr_policy = vec_policies[i];
990 vlib_cli_output (vm, "[%u].-\tBSID: %U",
991 (u32) (sr_policy - sm->sr_policies),
992 format_ip6_address, &sr_policy->bsid);
993 vlib_cli_output (vm, "\tBehavior: %s",
994 (sr_policy->is_encap ? "Encapsulation" :
996 vlib_cli_output (vm, "\tType: %s",
998 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
999 vlib_cli_output (vm, "\tFIB table: %u",
1000 (sr_policy->fib_table !=
1001 (u32) ~ 0 ? sr_policy->fib_table : 0));
1002 vlib_cli_output (vm, "\tSegment Lists:");
1003 vec_foreach (sl_index, sr_policy->segments_lists)
1006 s = format (s, "\t[%u].- ", *sl_index);
1007 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1008 s = format (s, "< ");
1009 vec_foreach (addr, segment_list->segments)
1011 s = format (s, "%U, ", format_ip6_address, addr);
1013 s = format (s, "\b\b > ");
1014 s = format (s, "weight: %u", segment_list->weight);
1015 vlib_cli_output (vm, " %s", s);
1017 vlib_cli_output (vm, "-----------");
1023 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1024 .path = "show sr policies",
1025 .short_help = "show sr policies",
1026 .function = show_sr_policies_command_fn,
1030 /*************************** SR rewrite graph node ****************************/
1032 * @brief Trace for the SR Policy Rewrite graph node
1035 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1038 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1039 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1040 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1043 (s, "SR-policy-rewrite: src %U dst %U",
1044 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1050 * @brief IPv6 encapsulation processing as per RFC2473
1052 static_always_inline void
1053 encaps_processing_v6 (vlib_node_runtime_t * node,
1055 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1059 ip0_encap->hop_limit -= 1;
1061 ip0->payload_length + sizeof (ip6_header_t) +
1062 clib_net_to_host_u16 (ip0_encap->payload_length);
1063 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1064 ip0->ip_version_traffic_class_and_flow_label =
1065 ip0_encap->ip_version_traffic_class_and_flow_label;
1069 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1072 sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1073 vlib_frame_t * from_frame)
1075 ip6_sr_main_t *sm = &sr_main;
1076 u32 n_left_from, next_index, *from, *to_next;
1078 from = vlib_frame_vector_args (from_frame);
1079 n_left_from = from_frame->n_vectors;
1081 next_index = node->cached_next_index;
1083 int encap_pkts = 0, bsid_pkts = 0;
1085 while (n_left_from > 0)
1089 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1092 while (n_left_from >= 8 && n_left_to_next >= 4)
1094 u32 bi0, bi1, bi2, bi3;
1095 vlib_buffer_t *b0, *b1, *b2, *b3;
1096 u32 next0, next1, next2, next3;
1097 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1098 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1099 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1100 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1102 /* Prefetch next iteration. */
1104 vlib_buffer_t *p4, *p5, *p6, *p7;
1106 p4 = vlib_get_buffer (vm, from[4]);
1107 p5 = vlib_get_buffer (vm, from[5]);
1108 p6 = vlib_get_buffer (vm, from[6]);
1109 p7 = vlib_get_buffer (vm, from[7]);
1111 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1112 vlib_prefetch_buffer_header (p4, LOAD);
1113 vlib_prefetch_buffer_header (p5, LOAD);
1114 vlib_prefetch_buffer_header (p6, LOAD);
1115 vlib_prefetch_buffer_header (p7, LOAD);
1117 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1118 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1119 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1120 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1123 to_next[0] = bi0 = from[0];
1124 to_next[1] = bi1 = from[1];
1125 to_next[2] = bi2 = from[2];
1126 to_next[3] = bi3 = from[3];
1130 n_left_to_next -= 4;
1132 b0 = vlib_get_buffer (vm, bi0);
1133 b1 = vlib_get_buffer (vm, bi1);
1134 b2 = vlib_get_buffer (vm, bi2);
1135 b3 = vlib_get_buffer (vm, bi3);
1138 pool_elt_at_index (sm->sid_lists,
1139 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1141 pool_elt_at_index (sm->sid_lists,
1142 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1144 pool_elt_at_index (sm->sid_lists,
1145 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1147 pool_elt_at_index (sm->sid_lists,
1148 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1150 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1151 (vec_len (sl0->rewrite) + b0->current_data));
1152 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1153 (vec_len (sl1->rewrite) + b1->current_data));
1154 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1155 (vec_len (sl2->rewrite) + b2->current_data));
1156 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1157 (vec_len (sl3->rewrite) + b3->current_data));
1159 ip0_encap = vlib_buffer_get_current (b0);
1160 ip1_encap = vlib_buffer_get_current (b1);
1161 ip2_encap = vlib_buffer_get_current (b2);
1162 ip3_encap = vlib_buffer_get_current (b3);
1164 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1165 sl0->rewrite, vec_len (sl0->rewrite));
1166 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1167 sl1->rewrite, vec_len (sl1->rewrite));
1168 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1169 sl2->rewrite, vec_len (sl2->rewrite));
1170 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1171 sl3->rewrite, vec_len (sl3->rewrite));
1173 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1174 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1175 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1176 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1178 ip0 = vlib_buffer_get_current (b0);
1179 ip1 = vlib_buffer_get_current (b1);
1180 ip2 = vlib_buffer_get_current (b2);
1181 ip3 = vlib_buffer_get_current (b3);
1183 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1184 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1185 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1186 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1188 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1190 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1192 sr_policy_rewrite_trace_t *tr =
1193 vlib_add_trace (vm, node, b0, sizeof (*tr));
1194 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1195 sizeof (tr->src.as_u8));
1196 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1197 sizeof (tr->dst.as_u8));
1200 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1202 sr_policy_rewrite_trace_t *tr =
1203 vlib_add_trace (vm, node, b1, sizeof (*tr));
1204 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1205 sizeof (tr->src.as_u8));
1206 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1207 sizeof (tr->dst.as_u8));
1210 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1212 sr_policy_rewrite_trace_t *tr =
1213 vlib_add_trace (vm, node, b2, sizeof (*tr));
1214 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1215 sizeof (tr->src.as_u8));
1216 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1217 sizeof (tr->dst.as_u8));
1220 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1222 sr_policy_rewrite_trace_t *tr =
1223 vlib_add_trace (vm, node, b3, sizeof (*tr));
1224 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1225 sizeof (tr->src.as_u8));
1226 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1227 sizeof (tr->dst.as_u8));
1232 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1233 n_left_to_next, bi0, bi1, bi2, bi3,
1234 next0, next1, next2, next3);
1237 /* Single loop for potentially the last three packets */
1238 while (n_left_from > 0 && n_left_to_next > 0)
1242 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1244 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1251 n_left_to_next -= 1;
1252 b0 = vlib_get_buffer (vm, bi0);
1255 pool_elt_at_index (sm->sid_lists,
1256 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1258 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1259 (vec_len (sl0->rewrite) + b0->current_data));
1261 ip0_encap = vlib_buffer_get_current (b0);
1263 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1264 sl0->rewrite, vec_len (sl0->rewrite));
1265 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1267 ip0 = vlib_buffer_get_current (b0);
1269 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1271 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1272 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1274 sr_policy_rewrite_trace_t *tr =
1275 vlib_add_trace (vm, node, b0, sizeof (*tr));
1276 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1277 sizeof (tr->src.as_u8));
1278 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1279 sizeof (tr->dst.as_u8));
1283 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1284 n_left_to_next, bi0, next0);
1287 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1290 /* Update counters */
1291 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1292 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1294 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1295 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1298 return from_frame->n_vectors;
1302 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1303 .function = sr_policy_rewrite_encaps,
1304 .name = "sr-pl-rewrite-encaps",
1305 .vector_size = sizeof (u32),
1306 .format_trace = format_sr_policy_rewrite_trace,
1307 .type = VLIB_NODE_TYPE_INTERNAL,
1308 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1309 .error_strings = sr_policy_rewrite_error_strings,
1310 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1312 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1313 foreach_sr_policy_rewrite_next
1320 * @brief IPv4 encapsulation processing as per RFC2473
1322 static_always_inline void
1323 encaps_processing_v4 (vlib_node_runtime_t * node,
1325 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1328 ip6_sr_header_t *sr0;
1332 /* Inner IPv4: Decrement TTL & update checksum */
1333 ip0_encap->ttl -= 1;
1334 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1335 checksum0 += checksum0 >= 0xffff;
1336 ip0_encap->checksum = checksum0;
1338 /* Outer IPv6: Update length, FL, proto */
1339 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1340 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1341 ip0->ip_version_traffic_class_and_flow_label =
1342 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1343 ((ip0_encap->tos & 0xFF) << 20));
1344 sr0 = (void *) (ip0 + 1);
1345 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1349 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1352 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1353 vlib_frame_t * from_frame)
1355 ip6_sr_main_t *sm = &sr_main;
1356 u32 n_left_from, next_index, *from, *to_next;
1358 from = vlib_frame_vector_args (from_frame);
1359 n_left_from = from_frame->n_vectors;
1361 next_index = node->cached_next_index;
1363 int encap_pkts = 0, bsid_pkts = 0;
1365 while (n_left_from > 0)
1369 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1372 while (n_left_from >= 8 && n_left_to_next >= 4)
1374 u32 bi0, bi1, bi2, bi3;
1375 vlib_buffer_t *b0, *b1, *b2, *b3;
1376 u32 next0, next1, next2, next3;
1377 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1378 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1379 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1380 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1382 /* Prefetch next iteration. */
1384 vlib_buffer_t *p4, *p5, *p6, *p7;
1386 p4 = vlib_get_buffer (vm, from[4]);
1387 p5 = vlib_get_buffer (vm, from[5]);
1388 p6 = vlib_get_buffer (vm, from[6]);
1389 p7 = vlib_get_buffer (vm, from[7]);
1391 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1392 vlib_prefetch_buffer_header (p4, LOAD);
1393 vlib_prefetch_buffer_header (p5, LOAD);
1394 vlib_prefetch_buffer_header (p6, LOAD);
1395 vlib_prefetch_buffer_header (p7, LOAD);
1397 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1398 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1399 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1400 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1403 to_next[0] = bi0 = from[0];
1404 to_next[1] = bi1 = from[1];
1405 to_next[2] = bi2 = from[2];
1406 to_next[3] = bi3 = from[3];
1410 n_left_to_next -= 4;
1412 b0 = vlib_get_buffer (vm, bi0);
1413 b1 = vlib_get_buffer (vm, bi1);
1414 b2 = vlib_get_buffer (vm, bi2);
1415 b3 = vlib_get_buffer (vm, bi3);
1418 pool_elt_at_index (sm->sid_lists,
1419 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1421 pool_elt_at_index (sm->sid_lists,
1422 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1424 pool_elt_at_index (sm->sid_lists,
1425 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1427 pool_elt_at_index (sm->sid_lists,
1428 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1430 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1431 (vec_len (sl0->rewrite) + b0->current_data));
1432 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1433 (vec_len (sl1->rewrite) + b1->current_data));
1434 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1435 (vec_len (sl2->rewrite) + b2->current_data));
1436 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1437 (vec_len (sl3->rewrite) + b3->current_data));
1439 ip0_encap = vlib_buffer_get_current (b0);
1440 ip1_encap = vlib_buffer_get_current (b1);
1441 ip2_encap = vlib_buffer_get_current (b2);
1442 ip3_encap = vlib_buffer_get_current (b3);
1444 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1445 sl0->rewrite, vec_len (sl0->rewrite));
1446 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1447 sl1->rewrite, vec_len (sl1->rewrite));
1448 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1449 sl2->rewrite, vec_len (sl2->rewrite));
1450 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1451 sl3->rewrite, vec_len (sl3->rewrite));
1453 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1454 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1455 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1456 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1458 ip0 = vlib_buffer_get_current (b0);
1459 ip1 = vlib_buffer_get_current (b1);
1460 ip2 = vlib_buffer_get_current (b2);
1461 ip3 = vlib_buffer_get_current (b3);
1463 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1464 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1465 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1466 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1468 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1470 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1472 sr_policy_rewrite_trace_t *tr =
1473 vlib_add_trace (vm, node, b0, sizeof (*tr));
1474 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1475 sizeof (tr->src.as_u8));
1476 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1477 sizeof (tr->dst.as_u8));
1480 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1482 sr_policy_rewrite_trace_t *tr =
1483 vlib_add_trace (vm, node, b1, sizeof (*tr));
1484 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1485 sizeof (tr->src.as_u8));
1486 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1487 sizeof (tr->dst.as_u8));
1490 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1492 sr_policy_rewrite_trace_t *tr =
1493 vlib_add_trace (vm, node, b2, sizeof (*tr));
1494 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1495 sizeof (tr->src.as_u8));
1496 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1497 sizeof (tr->dst.as_u8));
1500 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1502 sr_policy_rewrite_trace_t *tr =
1503 vlib_add_trace (vm, node, b3, sizeof (*tr));
1504 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1505 sizeof (tr->src.as_u8));
1506 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1507 sizeof (tr->dst.as_u8));
1512 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1513 n_left_to_next, bi0, bi1, bi2, bi3,
1514 next0, next1, next2, next3);
1517 /* Single loop for potentially the last three packets */
1518 while (n_left_from > 0 && n_left_to_next > 0)
1522 ip6_header_t *ip0 = 0;
1523 ip4_header_t *ip0_encap = 0;
1525 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1532 n_left_to_next -= 1;
1533 b0 = vlib_get_buffer (vm, bi0);
1536 pool_elt_at_index (sm->sid_lists,
1537 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1539 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1540 (vec_len (sl0->rewrite) + b0->current_data));
1542 ip0_encap = vlib_buffer_get_current (b0);
1544 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1545 sl0->rewrite, vec_len (sl0->rewrite));
1546 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1548 ip0 = vlib_buffer_get_current (b0);
1550 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1552 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1553 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1555 sr_policy_rewrite_trace_t *tr =
1556 vlib_add_trace (vm, node, b0, sizeof (*tr));
1557 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1558 sizeof (tr->src.as_u8));
1559 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1560 sizeof (tr->dst.as_u8));
1564 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1565 n_left_to_next, bi0, next0);
1568 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1571 /* Update counters */
1572 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1573 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1575 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1576 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1579 return from_frame->n_vectors;
1583 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1584 .function = sr_policy_rewrite_encaps_v4,
1585 .name = "sr-pl-rewrite-encaps-v4",
1586 .vector_size = sizeof (u32),
1587 .format_trace = format_sr_policy_rewrite_trace,
1588 .type = VLIB_NODE_TYPE_INTERNAL,
1589 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1590 .error_strings = sr_policy_rewrite_error_strings,
1591 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1593 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1594 foreach_sr_policy_rewrite_next
1601 ip_flow_hash (void *data)
1603 ip4_header_t *iph = (ip4_header_t *) data;
1605 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1606 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1608 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1614 return (*((u64 *) m) & 0xffffffffffff);
1618 l2_flow_hash (vlib_buffer_t * b0)
1620 ethernet_header_t *eh;
1622 uword is_ip, eh_size;
1625 eh = vlib_buffer_get_current (b0);
1626 eh_type = clib_net_to_host_u16 (eh->type);
1627 eh_size = ethernet_buffer_header_size (b0);
1629 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1631 /* since we have 2 cache lines, use them */
1633 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1637 b = mac_to_u64 ((u8 *) eh->dst_address);
1638 c = mac_to_u64 ((u8 *) eh->src_address);
1639 hash_mix64 (a, b, c);
1645 * @brief Graph node for applying a SR policy into a L2 frame
1648 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1649 vlib_frame_t * from_frame)
1651 ip6_sr_main_t *sm = &sr_main;
1652 u32 n_left_from, next_index, *from, *to_next;
1654 from = vlib_frame_vector_args (from_frame);
1655 n_left_from = from_frame->n_vectors;
1657 next_index = node->cached_next_index;
1659 int encap_pkts = 0, bsid_pkts = 0;
1661 while (n_left_from > 0)
1665 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1668 while (n_left_from >= 8 && n_left_to_next >= 4)
1670 u32 bi0, bi1, bi2, bi3;
1671 vlib_buffer_t *b0, *b1, *b2, *b3;
1672 u32 next0, next1, next2, next3;
1673 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1674 ethernet_header_t *en0, *en1, *en2, *en3;
1675 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1676 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1677 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1678 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1680 /* Prefetch next iteration. */
1682 vlib_buffer_t *p4, *p5, *p6, *p7;
1684 p4 = vlib_get_buffer (vm, from[4]);
1685 p5 = vlib_get_buffer (vm, from[5]);
1686 p6 = vlib_get_buffer (vm, from[6]);
1687 p7 = vlib_get_buffer (vm, from[7]);
1689 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1690 vlib_prefetch_buffer_header (p4, LOAD);
1691 vlib_prefetch_buffer_header (p5, LOAD);
1692 vlib_prefetch_buffer_header (p6, LOAD);
1693 vlib_prefetch_buffer_header (p7, LOAD);
1695 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1696 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1697 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1698 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1701 to_next[0] = bi0 = from[0];
1702 to_next[1] = bi1 = from[1];
1703 to_next[2] = bi2 = from[2];
1704 to_next[3] = bi3 = from[3];
1708 n_left_to_next -= 4;
1710 b0 = vlib_get_buffer (vm, bi0);
1711 b1 = vlib_get_buffer (vm, bi1);
1712 b2 = vlib_get_buffer (vm, bi2);
1713 b3 = vlib_get_buffer (vm, bi3);
1715 sp0 = pool_elt_at_index (sm->sr_policies,
1716 sm->sw_iface_sr_policies[vnet_buffer
1720 sp1 = pool_elt_at_index (sm->sr_policies,
1721 sm->sw_iface_sr_policies[vnet_buffer
1725 sp2 = pool_elt_at_index (sm->sr_policies,
1726 sm->sw_iface_sr_policies[vnet_buffer
1730 sp3 = pool_elt_at_index (sm->sr_policies,
1731 sm->sw_iface_sr_policies[vnet_buffer
1735 if (vec_len (sp0->segments_lists) == 1)
1736 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1739 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1740 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1741 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1742 (vec_len (sp0->segments_lists) - 1))];
1745 if (vec_len (sp1->segments_lists) == 1)
1746 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1749 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1750 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1751 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1752 (vec_len (sp1->segments_lists) - 1))];
1755 if (vec_len (sp2->segments_lists) == 1)
1756 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1759 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1760 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1761 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1762 (vec_len (sp2->segments_lists) - 1))];
1765 if (vec_len (sp3->segments_lists) == 1)
1766 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1769 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1770 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1771 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1772 (vec_len (sp3->segments_lists) - 1))];
1776 pool_elt_at_index (sm->sid_lists,
1777 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1779 pool_elt_at_index (sm->sid_lists,
1780 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1782 pool_elt_at_index (sm->sid_lists,
1783 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1785 pool_elt_at_index (sm->sid_lists,
1786 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1788 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1789 (vec_len (sl0->rewrite) + b0->current_data));
1790 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1791 (vec_len (sl1->rewrite) + b1->current_data));
1792 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1793 (vec_len (sl2->rewrite) + b2->current_data));
1794 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1795 (vec_len (sl3->rewrite) + b3->current_data));
1797 en0 = vlib_buffer_get_current (b0);
1798 en1 = vlib_buffer_get_current (b1);
1799 en2 = vlib_buffer_get_current (b2);
1800 en3 = vlib_buffer_get_current (b3);
1802 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1803 vec_len (sl0->rewrite));
1804 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1805 vec_len (sl1->rewrite));
1806 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1807 vec_len (sl2->rewrite));
1808 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1809 vec_len (sl3->rewrite));
1811 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1812 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1813 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1814 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1816 ip0 = vlib_buffer_get_current (b0);
1817 ip1 = vlib_buffer_get_current (b1);
1818 ip2 = vlib_buffer_get_current (b2);
1819 ip3 = vlib_buffer_get_current (b3);
1821 ip0->payload_length =
1822 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1823 ip1->payload_length =
1824 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1825 ip2->payload_length =
1826 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1827 ip3->payload_length =
1828 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1830 sr0 = (void *) (ip0 + 1);
1831 sr1 = (void *) (ip1 + 1);
1832 sr2 = (void *) (ip2 + 1);
1833 sr3 = (void *) (ip3 + 1);
1835 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1836 IP_PROTOCOL_IP6_NONXT;
1838 /* Which Traffic class and flow label do I set ? */
1839 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1841 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1843 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1845 sr_policy_rewrite_trace_t *tr =
1846 vlib_add_trace (vm, node, b0, sizeof (*tr));
1847 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1848 sizeof (tr->src.as_u8));
1849 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1850 sizeof (tr->dst.as_u8));
1853 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1855 sr_policy_rewrite_trace_t *tr =
1856 vlib_add_trace (vm, node, b1, sizeof (*tr));
1857 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1858 sizeof (tr->src.as_u8));
1859 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1860 sizeof (tr->dst.as_u8));
1863 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1865 sr_policy_rewrite_trace_t *tr =
1866 vlib_add_trace (vm, node, b2, sizeof (*tr));
1867 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1868 sizeof (tr->src.as_u8));
1869 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1870 sizeof (tr->dst.as_u8));
1873 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1875 sr_policy_rewrite_trace_t *tr =
1876 vlib_add_trace (vm, node, b3, sizeof (*tr));
1877 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1878 sizeof (tr->src.as_u8));
1879 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1880 sizeof (tr->dst.as_u8));
1885 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1886 n_left_to_next, bi0, bi1, bi2, bi3,
1887 next0, next1, next2, next3);
1890 /* Single loop for potentially the last three packets */
1891 while (n_left_from > 0 && n_left_to_next > 0)
1895 ip6_header_t *ip0 = 0;
1896 ip6_sr_header_t *sr0;
1897 ethernet_header_t *en0;
1898 ip6_sr_policy_t *sp0;
1900 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1907 n_left_to_next -= 1;
1908 b0 = vlib_get_buffer (vm, bi0);
1910 /* Find the SR policy */
1911 sp0 = pool_elt_at_index (sm->sr_policies,
1912 sm->sw_iface_sr_policies[vnet_buffer
1916 /* In case there is more than one SL, LB among them */
1917 if (vec_len (sp0->segments_lists) == 1)
1918 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1921 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1922 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1923 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1924 (vec_len (sp0->segments_lists) - 1))];
1927 pool_elt_at_index (sm->sid_lists,
1928 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1930 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1931 (vec_len (sl0->rewrite) + b0->current_data));
1933 en0 = vlib_buffer_get_current (b0);
1935 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1936 vec_len (sl0->rewrite));
1938 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1940 ip0 = vlib_buffer_get_current (b0);
1942 ip0->payload_length =
1943 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1945 sr0 = (void *) (ip0 + 1);
1946 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1948 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1949 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1951 sr_policy_rewrite_trace_t *tr =
1952 vlib_add_trace (vm, node, b0, sizeof (*tr));
1953 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1954 sizeof (tr->src.as_u8));
1955 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1956 sizeof (tr->dst.as_u8));
1960 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1961 n_left_to_next, bi0, next0);
1964 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1967 /* Update counters */
1968 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1969 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1971 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1972 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1975 return from_frame->n_vectors;
1979 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1980 .function = sr_policy_rewrite_encaps_l2,
1981 .name = "sr-pl-rewrite-encaps-l2",
1982 .vector_size = sizeof (u32),
1983 .format_trace = format_sr_policy_rewrite_trace,
1984 .type = VLIB_NODE_TYPE_INTERNAL,
1985 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1986 .error_strings = sr_policy_rewrite_error_strings,
1987 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1989 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1990 foreach_sr_policy_rewrite_next
1997 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2000 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2001 vlib_frame_t * from_frame)
2003 ip6_sr_main_t *sm = &sr_main;
2004 u32 n_left_from, next_index, *from, *to_next;
2006 from = vlib_frame_vector_args (from_frame);
2007 n_left_from = from_frame->n_vectors;
2009 next_index = node->cached_next_index;
2011 int insert_pkts = 0, bsid_pkts = 0;
2013 while (n_left_from > 0)
2017 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2020 while (n_left_from >= 8 && n_left_to_next >= 4)
2022 u32 bi0, bi1, bi2, bi3;
2023 vlib_buffer_t *b0, *b1, *b2, *b3;
2024 u32 next0, next1, next2, next3;
2025 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2026 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2027 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2028 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2029 u16 new_l0, new_l1, new_l2, new_l3;
2031 /* Prefetch next iteration. */
2033 vlib_buffer_t *p4, *p5, *p6, *p7;
2035 p4 = vlib_get_buffer (vm, from[4]);
2036 p5 = vlib_get_buffer (vm, from[5]);
2037 p6 = vlib_get_buffer (vm, from[6]);
2038 p7 = vlib_get_buffer (vm, from[7]);
2040 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2041 vlib_prefetch_buffer_header (p4, LOAD);
2042 vlib_prefetch_buffer_header (p5, LOAD);
2043 vlib_prefetch_buffer_header (p6, LOAD);
2044 vlib_prefetch_buffer_header (p7, LOAD);
2046 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2047 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2048 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2049 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2052 to_next[0] = bi0 = from[0];
2053 to_next[1] = bi1 = from[1];
2054 to_next[2] = bi2 = from[2];
2055 to_next[3] = bi3 = from[3];
2059 n_left_to_next -= 4;
2061 b0 = vlib_get_buffer (vm, bi0);
2062 b1 = vlib_get_buffer (vm, bi1);
2063 b2 = vlib_get_buffer (vm, bi2);
2064 b3 = vlib_get_buffer (vm, bi3);
2067 pool_elt_at_index (sm->sid_lists,
2068 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2070 pool_elt_at_index (sm->sid_lists,
2071 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2073 pool_elt_at_index (sm->sid_lists,
2074 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2076 pool_elt_at_index (sm->sid_lists,
2077 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2079 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2080 (vec_len (sl0->rewrite) + b0->current_data));
2081 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2082 (vec_len (sl1->rewrite) + b1->current_data));
2083 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2084 (vec_len (sl2->rewrite) + b2->current_data));
2085 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2086 (vec_len (sl3->rewrite) + b3->current_data));
2088 ip0 = vlib_buffer_get_current (b0);
2089 ip1 = vlib_buffer_get_current (b1);
2090 ip2 = vlib_buffer_get_current (b2);
2091 ip3 = vlib_buffer_get_current (b3);
2093 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2095 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2096 ip6_ext_header_len (ip0 + 1));
2098 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2100 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2102 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2103 ip6_ext_header_len (ip1 + 1));
2105 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2107 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2109 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2110 ip6_ext_header_len (ip2 + 1));
2112 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2114 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2116 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2117 ip6_ext_header_len (ip3 + 1));
2119 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2121 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2122 (void *) sr0 - (void *) ip0);
2123 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2124 (void *) sr1 - (void *) ip1);
2125 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2126 (void *) sr2 - (void *) ip2);
2127 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2128 (void *) sr3 - (void *) ip3);
2130 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2131 vec_len (sl0->rewrite));
2132 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2133 vec_len (sl1->rewrite));
2134 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2135 vec_len (sl2->rewrite));
2136 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2137 vec_len (sl3->rewrite));
2139 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2140 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2141 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2142 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2144 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2145 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2146 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2147 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2149 ip0->hop_limit -= 1;
2150 ip1->hop_limit -= 1;
2151 ip2->hop_limit -= 1;
2152 ip3->hop_limit -= 1;
2155 clib_net_to_host_u16 (ip0->payload_length) +
2156 vec_len (sl0->rewrite);
2158 clib_net_to_host_u16 (ip1->payload_length) +
2159 vec_len (sl1->rewrite);
2161 clib_net_to_host_u16 (ip2->payload_length) +
2162 vec_len (sl2->rewrite);
2164 clib_net_to_host_u16 (ip3->payload_length) +
2165 vec_len (sl3->rewrite);
2167 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2168 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2169 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2170 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2172 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2173 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2174 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2175 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2177 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2178 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2179 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2180 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2181 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2182 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2183 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2184 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2186 ip0->dst_address.as_u64[0] =
2187 (sr0->segments + sr0->segments_left)->as_u64[0];
2188 ip0->dst_address.as_u64[1] =
2189 (sr0->segments + sr0->segments_left)->as_u64[1];
2190 ip1->dst_address.as_u64[0] =
2191 (sr1->segments + sr1->segments_left)->as_u64[0];
2192 ip1->dst_address.as_u64[1] =
2193 (sr1->segments + sr1->segments_left)->as_u64[1];
2194 ip2->dst_address.as_u64[0] =
2195 (sr2->segments + sr2->segments_left)->as_u64[0];
2196 ip2->dst_address.as_u64[1] =
2197 (sr2->segments + sr2->segments_left)->as_u64[1];
2198 ip3->dst_address.as_u64[0] =
2199 (sr3->segments + sr3->segments_left)->as_u64[0];
2200 ip3->dst_address.as_u64[1] =
2201 (sr3->segments + sr3->segments_left)->as_u64[1];
2203 ip6_ext_header_t *ip_ext;
2204 if (ip0 + 1 == (void *) sr0)
2206 sr0->protocol = ip0->protocol;
2207 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2211 ip_ext = (void *) (ip0 + 1);
2212 sr0->protocol = ip_ext->next_hdr;
2213 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2216 if (ip1 + 1 == (void *) sr1)
2218 sr1->protocol = ip1->protocol;
2219 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2223 ip_ext = (void *) (ip2 + 1);
2224 sr2->protocol = ip_ext->next_hdr;
2225 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2228 if (ip2 + 1 == (void *) sr2)
2230 sr2->protocol = ip2->protocol;
2231 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2235 ip_ext = (void *) (ip2 + 1);
2236 sr2->protocol = ip_ext->next_hdr;
2237 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2240 if (ip3 + 1 == (void *) sr3)
2242 sr3->protocol = ip3->protocol;
2243 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2247 ip_ext = (void *) (ip3 + 1);
2248 sr3->protocol = ip_ext->next_hdr;
2249 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2254 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2256 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2258 sr_policy_rewrite_trace_t *tr =
2259 vlib_add_trace (vm, node, b0, sizeof (*tr));
2260 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2261 sizeof (tr->src.as_u8));
2262 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2263 sizeof (tr->dst.as_u8));
2266 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2268 sr_policy_rewrite_trace_t *tr =
2269 vlib_add_trace (vm, node, b1, sizeof (*tr));
2270 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2271 sizeof (tr->src.as_u8));
2272 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2273 sizeof (tr->dst.as_u8));
2276 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2278 sr_policy_rewrite_trace_t *tr =
2279 vlib_add_trace (vm, node, b2, sizeof (*tr));
2280 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2281 sizeof (tr->src.as_u8));
2282 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2283 sizeof (tr->dst.as_u8));
2286 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2288 sr_policy_rewrite_trace_t *tr =
2289 vlib_add_trace (vm, node, b3, sizeof (*tr));
2290 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2291 sizeof (tr->src.as_u8));
2292 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2293 sizeof (tr->dst.as_u8));
2297 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2298 n_left_to_next, bi0, bi1, bi2, bi3,
2299 next0, next1, next2, next3);
2302 /* Single loop for potentially the last three packets */
2303 while (n_left_from > 0 && n_left_to_next > 0)
2307 ip6_header_t *ip0 = 0;
2308 ip6_sr_header_t *sr0 = 0;
2310 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2318 n_left_to_next -= 1;
2320 b0 = vlib_get_buffer (vm, bi0);
2322 pool_elt_at_index (sm->sid_lists,
2323 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2324 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2325 (vec_len (sl0->rewrite) + b0->current_data));
2327 ip0 = vlib_buffer_get_current (b0);
2329 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2331 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2332 ip6_ext_header_len (ip0 + 1));
2334 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2336 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2337 (void *) sr0 - (void *) ip0);
2338 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2339 vec_len (sl0->rewrite));
2341 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2343 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2344 ip0->hop_limit -= 1;
2346 clib_net_to_host_u16 (ip0->payload_length) +
2347 vec_len (sl0->rewrite);
2348 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2350 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2351 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2352 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2354 ip0->dst_address.as_u64[0] =
2355 (sr0->segments + sr0->segments_left)->as_u64[0];
2356 ip0->dst_address.as_u64[1] =
2357 (sr0->segments + sr0->segments_left)->as_u64[1];
2359 if (ip0 + 1 == (void *) sr0)
2361 sr0->protocol = ip0->protocol;
2362 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2366 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2367 sr0->protocol = ip_ext->next_hdr;
2368 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2371 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2372 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2374 sr_policy_rewrite_trace_t *tr =
2375 vlib_add_trace (vm, node, b0, sizeof (*tr));
2376 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2377 sizeof (tr->src.as_u8));
2378 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2379 sizeof (tr->dst.as_u8));
2384 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2385 n_left_to_next, bi0, next0);
2388 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2391 /* Update counters */
2392 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2393 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2395 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2396 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2398 return from_frame->n_vectors;
2402 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2403 .function = sr_policy_rewrite_insert,
2404 .name = "sr-pl-rewrite-insert",
2405 .vector_size = sizeof (u32),
2406 .format_trace = format_sr_policy_rewrite_trace,
2407 .type = VLIB_NODE_TYPE_INTERNAL,
2408 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2409 .error_strings = sr_policy_rewrite_error_strings,
2410 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2412 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2413 foreach_sr_policy_rewrite_next
2420 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2423 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2424 vlib_frame_t * from_frame)
2426 ip6_sr_main_t *sm = &sr_main;
2427 u32 n_left_from, next_index, *from, *to_next;
2429 from = vlib_frame_vector_args (from_frame);
2430 n_left_from = from_frame->n_vectors;
2432 next_index = node->cached_next_index;
2434 int insert_pkts = 0, bsid_pkts = 0;
2436 while (n_left_from > 0)
2440 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2443 while (n_left_from >= 8 && n_left_to_next >= 4)
2445 u32 bi0, bi1, bi2, bi3;
2446 vlib_buffer_t *b0, *b1, *b2, *b3;
2447 u32 next0, next1, next2, next3;
2448 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2449 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2450 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2451 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2452 u16 new_l0, new_l1, new_l2, new_l3;
2454 /* Prefetch next iteration. */
2456 vlib_buffer_t *p4, *p5, *p6, *p7;
2458 p4 = vlib_get_buffer (vm, from[4]);
2459 p5 = vlib_get_buffer (vm, from[5]);
2460 p6 = vlib_get_buffer (vm, from[6]);
2461 p7 = vlib_get_buffer (vm, from[7]);
2463 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2464 vlib_prefetch_buffer_header (p4, LOAD);
2465 vlib_prefetch_buffer_header (p5, LOAD);
2466 vlib_prefetch_buffer_header (p6, LOAD);
2467 vlib_prefetch_buffer_header (p7, LOAD);
2469 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2470 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2471 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2472 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2475 to_next[0] = bi0 = from[0];
2476 to_next[1] = bi1 = from[1];
2477 to_next[2] = bi2 = from[2];
2478 to_next[3] = bi3 = from[3];
2482 n_left_to_next -= 4;
2484 b0 = vlib_get_buffer (vm, bi0);
2485 b1 = vlib_get_buffer (vm, bi1);
2486 b2 = vlib_get_buffer (vm, bi2);
2487 b3 = vlib_get_buffer (vm, bi3);
2490 pool_elt_at_index (sm->sid_lists,
2491 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2493 pool_elt_at_index (sm->sid_lists,
2494 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2496 pool_elt_at_index (sm->sid_lists,
2497 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2499 pool_elt_at_index (sm->sid_lists,
2500 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2502 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2503 (vec_len (sl0->rewrite_bsid) + b0->current_data));
2504 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2505 (vec_len (sl1->rewrite_bsid) + b1->current_data));
2506 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2507 (vec_len (sl2->rewrite_bsid) + b2->current_data));
2508 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2509 (vec_len (sl3->rewrite_bsid) + b3->current_data));
2511 ip0 = vlib_buffer_get_current (b0);
2512 ip1 = vlib_buffer_get_current (b1);
2513 ip2 = vlib_buffer_get_current (b2);
2514 ip3 = vlib_buffer_get_current (b3);
2516 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2518 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2519 ip6_ext_header_len (ip0 + 1));
2521 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2523 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2525 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2526 ip6_ext_header_len (ip1 + 1));
2528 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2530 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2532 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2533 ip6_ext_header_len (ip2 + 1));
2535 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2537 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2539 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2540 ip6_ext_header_len (ip3 + 1));
2542 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2544 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2545 (void *) sr0 - (void *) ip0);
2546 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2547 (void *) sr1 - (void *) ip1);
2548 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2549 (void *) sr2 - (void *) ip2);
2550 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2551 (void *) sr3 - (void *) ip3);
2553 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2554 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2555 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2556 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2557 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2558 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2559 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2560 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2562 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2563 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2564 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2565 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2567 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2568 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2569 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2570 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2572 ip0->hop_limit -= 1;
2573 ip1->hop_limit -= 1;
2574 ip2->hop_limit -= 1;
2575 ip3->hop_limit -= 1;
2578 clib_net_to_host_u16 (ip0->payload_length) +
2579 vec_len (sl0->rewrite_bsid);
2581 clib_net_to_host_u16 (ip1->payload_length) +
2582 vec_len (sl1->rewrite_bsid);
2584 clib_net_to_host_u16 (ip2->payload_length) +
2585 vec_len (sl2->rewrite_bsid);
2587 clib_net_to_host_u16 (ip3->payload_length) +
2588 vec_len (sl3->rewrite_bsid);
2590 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2591 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2592 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2593 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2595 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2596 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2597 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2598 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2600 ip0->dst_address.as_u64[0] =
2601 (sr0->segments + sr0->segments_left)->as_u64[0];
2602 ip0->dst_address.as_u64[1] =
2603 (sr0->segments + sr0->segments_left)->as_u64[1];
2604 ip1->dst_address.as_u64[0] =
2605 (sr1->segments + sr1->segments_left)->as_u64[0];
2606 ip1->dst_address.as_u64[1] =
2607 (sr1->segments + sr1->segments_left)->as_u64[1];
2608 ip2->dst_address.as_u64[0] =
2609 (sr2->segments + sr2->segments_left)->as_u64[0];
2610 ip2->dst_address.as_u64[1] =
2611 (sr2->segments + sr2->segments_left)->as_u64[1];
2612 ip3->dst_address.as_u64[0] =
2613 (sr3->segments + sr3->segments_left)->as_u64[0];
2614 ip3->dst_address.as_u64[1] =
2615 (sr3->segments + sr3->segments_left)->as_u64[1];
2617 ip6_ext_header_t *ip_ext;
2618 if (ip0 + 1 == (void *) sr0)
2620 sr0->protocol = ip0->protocol;
2621 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2625 ip_ext = (void *) (ip0 + 1);
2626 sr0->protocol = ip_ext->next_hdr;
2627 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2630 if (ip1 + 1 == (void *) sr1)
2632 sr1->protocol = ip1->protocol;
2633 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2637 ip_ext = (void *) (ip2 + 1);
2638 sr2->protocol = ip_ext->next_hdr;
2639 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2642 if (ip2 + 1 == (void *) sr2)
2644 sr2->protocol = ip2->protocol;
2645 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2649 ip_ext = (void *) (ip2 + 1);
2650 sr2->protocol = ip_ext->next_hdr;
2651 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2654 if (ip3 + 1 == (void *) sr3)
2656 sr3->protocol = ip3->protocol;
2657 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2661 ip_ext = (void *) (ip3 + 1);
2662 sr3->protocol = ip_ext->next_hdr;
2663 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2668 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2670 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2672 sr_policy_rewrite_trace_t *tr =
2673 vlib_add_trace (vm, node, b0, sizeof (*tr));
2674 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2675 sizeof (tr->src.as_u8));
2676 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2677 sizeof (tr->dst.as_u8));
2680 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2682 sr_policy_rewrite_trace_t *tr =
2683 vlib_add_trace (vm, node, b1, sizeof (*tr));
2684 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2685 sizeof (tr->src.as_u8));
2686 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2687 sizeof (tr->dst.as_u8));
2690 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2692 sr_policy_rewrite_trace_t *tr =
2693 vlib_add_trace (vm, node, b2, sizeof (*tr));
2694 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2695 sizeof (tr->src.as_u8));
2696 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2697 sizeof (tr->dst.as_u8));
2700 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2702 sr_policy_rewrite_trace_t *tr =
2703 vlib_add_trace (vm, node, b3, sizeof (*tr));
2704 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2705 sizeof (tr->src.as_u8));
2706 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2707 sizeof (tr->dst.as_u8));
2711 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2712 n_left_to_next, bi0, bi1, bi2, bi3,
2713 next0, next1, next2, next3);
2716 /* Single loop for potentially the last three packets */
2717 while (n_left_from > 0 && n_left_to_next > 0)
2721 ip6_header_t *ip0 = 0;
2722 ip6_sr_header_t *sr0 = 0;
2724 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2732 n_left_to_next -= 1;
2734 b0 = vlib_get_buffer (vm, bi0);
2736 pool_elt_at_index (sm->sid_lists,
2737 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2738 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2739 (vec_len (sl0->rewrite_bsid) + b0->current_data));
2741 ip0 = vlib_buffer_get_current (b0);
2743 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2745 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2746 ip6_ext_header_len (ip0 + 1));
2748 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2750 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2751 (void *) sr0 - (void *) ip0);
2752 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2753 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2755 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2757 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2758 ip0->hop_limit -= 1;
2760 clib_net_to_host_u16 (ip0->payload_length) +
2761 vec_len (sl0->rewrite_bsid);
2762 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2764 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2766 ip0->dst_address.as_u64[0] =
2767 (sr0->segments + sr0->segments_left)->as_u64[0];
2768 ip0->dst_address.as_u64[1] =
2769 (sr0->segments + sr0->segments_left)->as_u64[1];
2771 if (ip0 + 1 == (void *) sr0)
2773 sr0->protocol = ip0->protocol;
2774 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2778 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2779 sr0->protocol = ip_ext->next_hdr;
2780 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2783 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2784 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2786 sr_policy_rewrite_trace_t *tr =
2787 vlib_add_trace (vm, node, b0, sizeof (*tr));
2788 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2789 sizeof (tr->src.as_u8));
2790 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2791 sizeof (tr->dst.as_u8));
2796 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2797 n_left_to_next, bi0, next0);
2800 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2803 /* Update counters */
2804 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2805 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2807 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2808 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2810 return from_frame->n_vectors;
2814 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2815 .function = sr_policy_rewrite_b_insert,
2816 .name = "sr-pl-rewrite-b-insert",
2817 .vector_size = sizeof (u32),
2818 .format_trace = format_sr_policy_rewrite_trace,
2819 .type = VLIB_NODE_TYPE_INTERNAL,
2820 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2821 .error_strings = sr_policy_rewrite_error_strings,
2822 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2824 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2825 foreach_sr_policy_rewrite_next
2832 * @brief Function BSID encapsulation
2834 static_always_inline void
2835 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2838 ip6_sr_header_t * sr0, u32 * next0)
2840 ip6_address_t *new_dst0;
2842 if (PREDICT_FALSE (!sr0))
2843 goto error_bsid_encaps;
2845 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2847 if (PREDICT_TRUE (sr0->segments_left != 0))
2849 sr0->segments_left -= 1;
2850 new_dst0 = (ip6_address_t *) (sr0->segments);
2851 new_dst0 += sr0->segments_left;
2852 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2853 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2859 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2860 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2864 * @brief Graph node for applying a SR policy BSID - Encapsulation
2867 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2868 vlib_frame_t * from_frame)
2870 ip6_sr_main_t *sm = &sr_main;
2871 u32 n_left_from, next_index, *from, *to_next;
2873 from = vlib_frame_vector_args (from_frame);
2874 n_left_from = from_frame->n_vectors;
2876 next_index = node->cached_next_index;
2878 int encap_pkts = 0, bsid_pkts = 0;
2880 while (n_left_from > 0)
2884 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2887 while (n_left_from >= 8 && n_left_to_next >= 4)
2889 u32 bi0, bi1, bi2, bi3;
2890 vlib_buffer_t *b0, *b1, *b2, *b3;
2891 u32 next0, next1, next2, next3;
2892 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2893 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2894 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2895 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2896 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2897 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2899 /* Prefetch next iteration. */
2901 vlib_buffer_t *p4, *p5, *p6, *p7;
2903 p4 = vlib_get_buffer (vm, from[4]);
2904 p5 = vlib_get_buffer (vm, from[5]);
2905 p6 = vlib_get_buffer (vm, from[6]);
2906 p7 = vlib_get_buffer (vm, from[7]);
2908 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2909 vlib_prefetch_buffer_header (p4, LOAD);
2910 vlib_prefetch_buffer_header (p5, LOAD);
2911 vlib_prefetch_buffer_header (p6, LOAD);
2912 vlib_prefetch_buffer_header (p7, LOAD);
2914 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2915 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2916 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2917 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2920 to_next[0] = bi0 = from[0];
2921 to_next[1] = bi1 = from[1];
2922 to_next[2] = bi2 = from[2];
2923 to_next[3] = bi3 = from[3];
2927 n_left_to_next -= 4;
2929 b0 = vlib_get_buffer (vm, bi0);
2930 b1 = vlib_get_buffer (vm, bi1);
2931 b2 = vlib_get_buffer (vm, bi2);
2932 b3 = vlib_get_buffer (vm, bi3);
2935 pool_elt_at_index (sm->sid_lists,
2936 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2938 pool_elt_at_index (sm->sid_lists,
2939 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2941 pool_elt_at_index (sm->sid_lists,
2942 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2944 pool_elt_at_index (sm->sid_lists,
2945 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2947 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2948 (vec_len (sl0->rewrite) + b0->current_data));
2949 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2950 (vec_len (sl1->rewrite) + b1->current_data));
2951 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2952 (vec_len (sl2->rewrite) + b2->current_data));
2953 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2954 (vec_len (sl3->rewrite) + b3->current_data));
2956 ip0_encap = vlib_buffer_get_current (b0);
2957 ip1_encap = vlib_buffer_get_current (b1);
2958 ip2_encap = vlib_buffer_get_current (b2);
2959 ip3_encap = vlib_buffer_get_current (b3);
2961 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2962 IP_PROTOCOL_IPV6_ROUTE);
2963 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2964 IP_PROTOCOL_IPV6_ROUTE);
2965 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2966 IP_PROTOCOL_IPV6_ROUTE);
2967 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2968 IP_PROTOCOL_IPV6_ROUTE);
2970 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2971 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2972 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2973 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2975 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2976 sl0->rewrite, vec_len (sl0->rewrite));
2977 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2978 sl1->rewrite, vec_len (sl1->rewrite));
2979 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2980 sl2->rewrite, vec_len (sl2->rewrite));
2981 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2982 sl3->rewrite, vec_len (sl3->rewrite));
2984 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2985 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2986 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2987 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2989 ip0 = vlib_buffer_get_current (b0);
2990 ip1 = vlib_buffer_get_current (b1);
2991 ip2 = vlib_buffer_get_current (b2);
2992 ip3 = vlib_buffer_get_current (b3);
2994 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2995 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2996 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2997 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2999 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3001 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3003 sr_policy_rewrite_trace_t *tr =
3004 vlib_add_trace (vm, node, b0, sizeof (*tr));
3005 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3006 sizeof (tr->src.as_u8));
3007 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3008 sizeof (tr->dst.as_u8));
3011 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3013 sr_policy_rewrite_trace_t *tr =
3014 vlib_add_trace (vm, node, b1, sizeof (*tr));
3015 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3016 sizeof (tr->src.as_u8));
3017 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3018 sizeof (tr->dst.as_u8));
3021 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3023 sr_policy_rewrite_trace_t *tr =
3024 vlib_add_trace (vm, node, b2, sizeof (*tr));
3025 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3026 sizeof (tr->src.as_u8));
3027 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3028 sizeof (tr->dst.as_u8));
3031 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3033 sr_policy_rewrite_trace_t *tr =
3034 vlib_add_trace (vm, node, b3, sizeof (*tr));
3035 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3036 sizeof (tr->src.as_u8));
3037 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3038 sizeof (tr->dst.as_u8));
3043 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3044 n_left_to_next, bi0, bi1, bi2, bi3,
3045 next0, next1, next2, next3);
3048 /* Single loop for potentially the last three packets */
3049 while (n_left_from > 0 && n_left_to_next > 0)
3053 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3054 ip6_ext_header_t *prev0;
3055 ip6_sr_header_t *sr0;
3057 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3064 n_left_to_next -= 1;
3065 b0 = vlib_get_buffer (vm, bi0);
3068 pool_elt_at_index (sm->sid_lists,
3069 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3071 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
3072 (vec_len (sl0->rewrite) + b0->current_data));
3074 ip0_encap = vlib_buffer_get_current (b0);
3075 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3076 IP_PROTOCOL_IPV6_ROUTE);
3077 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3079 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3080 sl0->rewrite, vec_len (sl0->rewrite));
3081 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3083 ip0 = vlib_buffer_get_current (b0);
3085 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3087 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3088 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3090 sr_policy_rewrite_trace_t *tr =
3091 vlib_add_trace (vm, node, b0, sizeof (*tr));
3092 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3093 sizeof (tr->src.as_u8));
3094 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3095 sizeof (tr->dst.as_u8));
3099 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3100 n_left_to_next, bi0, next0);
3103 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3106 /* Update counters */
3107 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3108 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3110 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3111 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3114 return from_frame->n_vectors;
3118 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3119 .function = sr_policy_rewrite_b_encaps,
3120 .name = "sr-pl-rewrite-b-encaps",
3121 .vector_size = sizeof (u32),
3122 .format_trace = format_sr_policy_rewrite_trace,
3123 .type = VLIB_NODE_TYPE_INTERNAL,
3124 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3125 .error_strings = sr_policy_rewrite_error_strings,
3126 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3128 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3129 foreach_sr_policy_rewrite_next
3135 /*************************** SR Segment Lists DPOs ****************************/
3137 format_sr_segment_list_dpo (u8 * s, va_list * args)
3139 ip6_sr_main_t *sm = &sr_main;
3140 ip6_address_t *addr;
3143 index_t index = va_arg (*args, index_t);
3144 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3145 s = format (s, "SR: Segment List index:[%d]", index);
3146 s = format (s, "\n\tSegments:");
3148 sl = pool_elt_at_index (sm->sid_lists, index);
3150 s = format (s, "< ");
3151 vec_foreach (addr, sl->segments)
3153 s = format (s, "%U, ", format_ip6_address, addr);
3155 s = format (s, "\b\b > - ");
3156 s = format (s, "Weight: %u", sl->weight);
3161 const static dpo_vft_t sr_policy_rewrite_vft = {
3162 .dv_lock = sr_dpo_lock,
3163 .dv_unlock = sr_dpo_unlock,
3164 .dv_format = format_sr_segment_list_dpo,
3167 const static char *const sr_pr_encaps_ip6_nodes[] = {
3168 "sr-pl-rewrite-encaps",
3172 const static char *const sr_pr_encaps_ip4_nodes[] = {
3173 "sr-pl-rewrite-encaps-v4",
3177 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3178 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3179 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3182 const static char *const sr_pr_insert_ip6_nodes[] = {
3183 "sr-pl-rewrite-insert",
3187 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3188 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3191 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3192 "sr-pl-rewrite-b-insert",
3196 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3197 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3200 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3201 "sr-pl-rewrite-b-encaps",
3205 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3206 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3209 /********************* SR Policy Rewrite initialization ***********************/
3211 * @brief SR Policy Rewrite initialization
3214 sr_policy_rewrite_init (vlib_main_t * vm)
3216 ip6_sr_main_t *sm = &sr_main;
3218 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3219 sm->sr_policy_index_by_key = hash_create_mem (0, sizeof (ip6_address_t),
3222 /* Init SR VPO DPOs type */
3223 sr_pr_encaps_dpo_type =
3224 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3226 sr_pr_insert_dpo_type =
3227 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3229 sr_pr_bsid_encaps_dpo_type =
3230 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3232 sr_pr_bsid_insert_dpo_type =
3233 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3235 /* Register the L2 encaps node used in HW redirect */
3236 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3238 sm->fib_table_ip6 = (u32) ~ 0;
3239 sm->fib_table_ip4 = (u32) ~ 0;
3244 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3248 * fd.io coding-style-patch-verification: ON
3251 * eval: (c-set-style "gnu")