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 (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1151 vec_len (sl0->rewrite));
1152 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1153 vec_len (sl1->rewrite));
1154 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1155 vec_len (sl2->rewrite));
1156 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1157 vec_len (sl3->rewrite));
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]);
1257 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1258 vec_len (sl0->rewrite));
1260 ip0_encap = vlib_buffer_get_current (b0);
1262 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1263 sl0->rewrite, vec_len (sl0->rewrite));
1264 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1266 ip0 = vlib_buffer_get_current (b0);
1268 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1270 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1271 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1273 sr_policy_rewrite_trace_t *tr =
1274 vlib_add_trace (vm, node, b0, sizeof (*tr));
1275 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1276 sizeof (tr->src.as_u8));
1277 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1278 sizeof (tr->dst.as_u8));
1282 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1283 n_left_to_next, bi0, next0);
1286 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1289 /* Update counters */
1290 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1291 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1293 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1294 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1297 return from_frame->n_vectors;
1301 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1302 .function = sr_policy_rewrite_encaps,
1303 .name = "sr-pl-rewrite-encaps",
1304 .vector_size = sizeof (u32),
1305 .format_trace = format_sr_policy_rewrite_trace,
1306 .type = VLIB_NODE_TYPE_INTERNAL,
1307 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1308 .error_strings = sr_policy_rewrite_error_strings,
1309 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1311 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1312 foreach_sr_policy_rewrite_next
1319 * @brief IPv4 encapsulation processing as per RFC2473
1321 static_always_inline void
1322 encaps_processing_v4 (vlib_node_runtime_t * node,
1324 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1327 ip6_sr_header_t *sr0;
1331 /* Inner IPv4: Decrement TTL & update checksum */
1332 ip0_encap->ttl -= 1;
1333 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1334 checksum0 += checksum0 >= 0xffff;
1335 ip0_encap->checksum = checksum0;
1337 /* Outer IPv6: Update length, FL, proto */
1338 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1339 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1340 ip0->ip_version_traffic_class_and_flow_label =
1341 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1342 ((ip0_encap->tos & 0xFF) << 20));
1343 sr0 = (void *) (ip0 + 1);
1344 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1348 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1351 sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1352 vlib_frame_t * from_frame)
1354 ip6_sr_main_t *sm = &sr_main;
1355 u32 n_left_from, next_index, *from, *to_next;
1357 from = vlib_frame_vector_args (from_frame);
1358 n_left_from = from_frame->n_vectors;
1360 next_index = node->cached_next_index;
1362 int encap_pkts = 0, bsid_pkts = 0;
1364 while (n_left_from > 0)
1368 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1371 while (n_left_from >= 8 && n_left_to_next >= 4)
1373 u32 bi0, bi1, bi2, bi3;
1374 vlib_buffer_t *b0, *b1, *b2, *b3;
1375 u32 next0, next1, next2, next3;
1376 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1377 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1378 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1379 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1381 /* Prefetch next iteration. */
1383 vlib_buffer_t *p4, *p5, *p6, *p7;
1385 p4 = vlib_get_buffer (vm, from[4]);
1386 p5 = vlib_get_buffer (vm, from[5]);
1387 p6 = vlib_get_buffer (vm, from[6]);
1388 p7 = vlib_get_buffer (vm, from[7]);
1390 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1391 vlib_prefetch_buffer_header (p4, LOAD);
1392 vlib_prefetch_buffer_header (p5, LOAD);
1393 vlib_prefetch_buffer_header (p6, LOAD);
1394 vlib_prefetch_buffer_header (p7, LOAD);
1396 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1397 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1398 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1399 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1402 to_next[0] = bi0 = from[0];
1403 to_next[1] = bi1 = from[1];
1404 to_next[2] = bi2 = from[2];
1405 to_next[3] = bi3 = from[3];
1409 n_left_to_next -= 4;
1411 b0 = vlib_get_buffer (vm, bi0);
1412 b1 = vlib_get_buffer (vm, bi1);
1413 b2 = vlib_get_buffer (vm, bi2);
1414 b3 = vlib_get_buffer (vm, bi3);
1417 pool_elt_at_index (sm->sid_lists,
1418 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1420 pool_elt_at_index (sm->sid_lists,
1421 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1423 pool_elt_at_index (sm->sid_lists,
1424 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1426 pool_elt_at_index (sm->sid_lists,
1427 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1428 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1429 vec_len (sl0->rewrite));
1430 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1431 vec_len (sl1->rewrite));
1432 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1433 vec_len (sl2->rewrite));
1434 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1435 vec_len (sl3->rewrite));
1437 ip0_encap = vlib_buffer_get_current (b0);
1438 ip1_encap = vlib_buffer_get_current (b1);
1439 ip2_encap = vlib_buffer_get_current (b2);
1440 ip3_encap = vlib_buffer_get_current (b3);
1442 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1443 sl0->rewrite, vec_len (sl0->rewrite));
1444 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1445 sl1->rewrite, vec_len (sl1->rewrite));
1446 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1447 sl2->rewrite, vec_len (sl2->rewrite));
1448 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1449 sl3->rewrite, vec_len (sl3->rewrite));
1451 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1452 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1453 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1454 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1456 ip0 = vlib_buffer_get_current (b0);
1457 ip1 = vlib_buffer_get_current (b1);
1458 ip2 = vlib_buffer_get_current (b2);
1459 ip3 = vlib_buffer_get_current (b3);
1461 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1462 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1463 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1464 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1466 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1468 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1470 sr_policy_rewrite_trace_t *tr =
1471 vlib_add_trace (vm, node, b0, sizeof (*tr));
1472 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1473 sizeof (tr->src.as_u8));
1474 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1475 sizeof (tr->dst.as_u8));
1478 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1480 sr_policy_rewrite_trace_t *tr =
1481 vlib_add_trace (vm, node, b1, sizeof (*tr));
1482 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1483 sizeof (tr->src.as_u8));
1484 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1485 sizeof (tr->dst.as_u8));
1488 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1490 sr_policy_rewrite_trace_t *tr =
1491 vlib_add_trace (vm, node, b2, sizeof (*tr));
1492 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1493 sizeof (tr->src.as_u8));
1494 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1495 sizeof (tr->dst.as_u8));
1498 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1500 sr_policy_rewrite_trace_t *tr =
1501 vlib_add_trace (vm, node, b3, sizeof (*tr));
1502 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1503 sizeof (tr->src.as_u8));
1504 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1505 sizeof (tr->dst.as_u8));
1510 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1511 n_left_to_next, bi0, bi1, bi2, bi3,
1512 next0, next1, next2, next3);
1515 /* Single loop for potentially the last three packets */
1516 while (n_left_from > 0 && n_left_to_next > 0)
1520 ip6_header_t *ip0 = 0;
1521 ip4_header_t *ip0_encap = 0;
1523 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1530 n_left_to_next -= 1;
1531 b0 = vlib_get_buffer (vm, bi0);
1534 pool_elt_at_index (sm->sid_lists,
1535 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1536 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1537 vec_len (sl0->rewrite));
1539 ip0_encap = vlib_buffer_get_current (b0);
1541 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1542 sl0->rewrite, vec_len (sl0->rewrite));
1543 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1545 ip0 = vlib_buffer_get_current (b0);
1547 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1549 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1550 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1552 sr_policy_rewrite_trace_t *tr =
1553 vlib_add_trace (vm, node, b0, sizeof (*tr));
1554 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1555 sizeof (tr->src.as_u8));
1556 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1557 sizeof (tr->dst.as_u8));
1561 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1562 n_left_to_next, bi0, next0);
1565 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1568 /* Update counters */
1569 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1570 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1572 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1573 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1576 return from_frame->n_vectors;
1580 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1581 .function = sr_policy_rewrite_encaps_v4,
1582 .name = "sr-pl-rewrite-encaps-v4",
1583 .vector_size = sizeof (u32),
1584 .format_trace = format_sr_policy_rewrite_trace,
1585 .type = VLIB_NODE_TYPE_INTERNAL,
1586 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1587 .error_strings = sr_policy_rewrite_error_strings,
1588 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1590 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1591 foreach_sr_policy_rewrite_next
1598 ip_flow_hash (void *data)
1600 ip4_header_t *iph = (ip4_header_t *) data;
1602 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1603 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1605 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1611 return (*((u64 *) m) & 0xffffffffffff);
1615 l2_flow_hash (vlib_buffer_t * b0)
1617 ethernet_header_t *eh;
1619 uword is_ip, eh_size;
1622 eh = vlib_buffer_get_current (b0);
1623 eh_type = clib_net_to_host_u16 (eh->type);
1624 eh_size = ethernet_buffer_header_size (b0);
1626 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1628 /* since we have 2 cache lines, use them */
1630 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1634 b = mac_to_u64 ((u8 *) eh->dst_address);
1635 c = mac_to_u64 ((u8 *) eh->src_address);
1636 hash_mix64 (a, b, c);
1642 * @brief Graph node for applying a SR policy into a L2 frame
1645 sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1646 vlib_frame_t * from_frame)
1648 ip6_sr_main_t *sm = &sr_main;
1649 u32 n_left_from, next_index, *from, *to_next;
1651 from = vlib_frame_vector_args (from_frame);
1652 n_left_from = from_frame->n_vectors;
1654 next_index = node->cached_next_index;
1656 int encap_pkts = 0, bsid_pkts = 0;
1658 while (n_left_from > 0)
1662 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1665 while (n_left_from >= 8 && n_left_to_next >= 4)
1667 u32 bi0, bi1, bi2, bi3;
1668 vlib_buffer_t *b0, *b1, *b2, *b3;
1669 u32 next0, next1, next2, next3;
1670 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1671 ethernet_header_t *en0, *en1, *en2, *en3;
1672 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1673 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1674 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1675 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1677 /* Prefetch next iteration. */
1679 vlib_buffer_t *p4, *p5, *p6, *p7;
1681 p4 = vlib_get_buffer (vm, from[4]);
1682 p5 = vlib_get_buffer (vm, from[5]);
1683 p6 = vlib_get_buffer (vm, from[6]);
1684 p7 = vlib_get_buffer (vm, from[7]);
1686 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1687 vlib_prefetch_buffer_header (p4, LOAD);
1688 vlib_prefetch_buffer_header (p5, LOAD);
1689 vlib_prefetch_buffer_header (p6, LOAD);
1690 vlib_prefetch_buffer_header (p7, LOAD);
1692 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1693 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1694 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1695 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1698 to_next[0] = bi0 = from[0];
1699 to_next[1] = bi1 = from[1];
1700 to_next[2] = bi2 = from[2];
1701 to_next[3] = bi3 = from[3];
1705 n_left_to_next -= 4;
1707 b0 = vlib_get_buffer (vm, bi0);
1708 b1 = vlib_get_buffer (vm, bi1);
1709 b2 = vlib_get_buffer (vm, bi2);
1710 b3 = vlib_get_buffer (vm, bi3);
1712 sp0 = pool_elt_at_index (sm->sr_policies,
1713 sm->sw_iface_sr_policies[vnet_buffer
1717 sp1 = pool_elt_at_index (sm->sr_policies,
1718 sm->sw_iface_sr_policies[vnet_buffer
1722 sp2 = pool_elt_at_index (sm->sr_policies,
1723 sm->sw_iface_sr_policies[vnet_buffer
1727 sp3 = pool_elt_at_index (sm->sr_policies,
1728 sm->sw_iface_sr_policies[vnet_buffer
1732 if (vec_len (sp0->segments_lists) == 1)
1733 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1736 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1737 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1738 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1739 (vec_len (sp0->segments_lists) - 1))];
1742 if (vec_len (sp1->segments_lists) == 1)
1743 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1746 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1747 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1748 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1749 (vec_len (sp1->segments_lists) - 1))];
1752 if (vec_len (sp2->segments_lists) == 1)
1753 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1756 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1757 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1758 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1759 (vec_len (sp2->segments_lists) - 1))];
1762 if (vec_len (sp3->segments_lists) == 1)
1763 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1766 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1767 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1768 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1769 (vec_len (sp3->segments_lists) - 1))];
1773 pool_elt_at_index (sm->sid_lists,
1774 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1776 pool_elt_at_index (sm->sid_lists,
1777 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1779 pool_elt_at_index (sm->sid_lists,
1780 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1782 pool_elt_at_index (sm->sid_lists,
1783 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1785 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1786 vec_len (sl0->rewrite));
1787 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1788 vec_len (sl1->rewrite));
1789 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1790 vec_len (sl2->rewrite));
1791 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1792 vec_len (sl3->rewrite));
1794 en0 = vlib_buffer_get_current (b0);
1795 en1 = vlib_buffer_get_current (b1);
1796 en2 = vlib_buffer_get_current (b2);
1797 en3 = vlib_buffer_get_current (b3);
1799 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1800 vec_len (sl0->rewrite));
1801 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1802 vec_len (sl1->rewrite));
1803 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1804 vec_len (sl2->rewrite));
1805 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1806 vec_len (sl3->rewrite));
1808 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1809 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1810 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1811 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1813 ip0 = vlib_buffer_get_current (b0);
1814 ip1 = vlib_buffer_get_current (b1);
1815 ip2 = vlib_buffer_get_current (b2);
1816 ip3 = vlib_buffer_get_current (b3);
1818 ip0->payload_length =
1819 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1820 ip1->payload_length =
1821 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1822 ip2->payload_length =
1823 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1824 ip3->payload_length =
1825 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1827 sr0 = (void *) (ip0 + 1);
1828 sr1 = (void *) (ip1 + 1);
1829 sr2 = (void *) (ip2 + 1);
1830 sr3 = (void *) (ip3 + 1);
1832 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1833 IP_PROTOCOL_IP6_NONXT;
1835 /* Which Traffic class and flow label do I set ? */
1836 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1838 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1840 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1842 sr_policy_rewrite_trace_t *tr =
1843 vlib_add_trace (vm, node, b0, sizeof (*tr));
1844 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1845 sizeof (tr->src.as_u8));
1846 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1847 sizeof (tr->dst.as_u8));
1850 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1852 sr_policy_rewrite_trace_t *tr =
1853 vlib_add_trace (vm, node, b1, sizeof (*tr));
1854 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1855 sizeof (tr->src.as_u8));
1856 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1857 sizeof (tr->dst.as_u8));
1860 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1862 sr_policy_rewrite_trace_t *tr =
1863 vlib_add_trace (vm, node, b2, sizeof (*tr));
1864 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1865 sizeof (tr->src.as_u8));
1866 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1867 sizeof (tr->dst.as_u8));
1870 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1872 sr_policy_rewrite_trace_t *tr =
1873 vlib_add_trace (vm, node, b3, sizeof (*tr));
1874 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1875 sizeof (tr->src.as_u8));
1876 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1877 sizeof (tr->dst.as_u8));
1882 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1883 n_left_to_next, bi0, bi1, bi2, bi3,
1884 next0, next1, next2, next3);
1887 /* Single loop for potentially the last three packets */
1888 while (n_left_from > 0 && n_left_to_next > 0)
1892 ip6_header_t *ip0 = 0;
1893 ip6_sr_header_t *sr0;
1894 ethernet_header_t *en0;
1895 ip6_sr_policy_t *sp0;
1897 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1904 n_left_to_next -= 1;
1905 b0 = vlib_get_buffer (vm, bi0);
1907 /* Find the SR policy */
1908 sp0 = pool_elt_at_index (sm->sr_policies,
1909 sm->sw_iface_sr_policies[vnet_buffer
1913 /* In case there is more than one SL, LB among them */
1914 if (vec_len (sp0->segments_lists) == 1)
1915 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1918 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1919 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1920 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1921 (vec_len (sp0->segments_lists) - 1))];
1924 pool_elt_at_index (sm->sid_lists,
1925 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1926 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1927 vec_len (sl0->rewrite));
1929 en0 = vlib_buffer_get_current (b0);
1931 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1932 vec_len (sl0->rewrite));
1934 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1936 ip0 = vlib_buffer_get_current (b0);
1938 ip0->payload_length =
1939 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1941 sr0 = (void *) (ip0 + 1);
1942 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1944 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1945 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1947 sr_policy_rewrite_trace_t *tr =
1948 vlib_add_trace (vm, node, b0, sizeof (*tr));
1949 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1950 sizeof (tr->src.as_u8));
1951 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1952 sizeof (tr->dst.as_u8));
1956 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1957 n_left_to_next, bi0, next0);
1960 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1963 /* Update counters */
1964 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1965 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1967 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1968 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1971 return from_frame->n_vectors;
1975 VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1976 .function = sr_policy_rewrite_encaps_l2,
1977 .name = "sr-pl-rewrite-encaps-l2",
1978 .vector_size = sizeof (u32),
1979 .format_trace = format_sr_policy_rewrite_trace,
1980 .type = VLIB_NODE_TYPE_INTERNAL,
1981 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1982 .error_strings = sr_policy_rewrite_error_strings,
1983 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1985 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1986 foreach_sr_policy_rewrite_next
1993 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1996 sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1997 vlib_frame_t * from_frame)
1999 ip6_sr_main_t *sm = &sr_main;
2000 u32 n_left_from, next_index, *from, *to_next;
2002 from = vlib_frame_vector_args (from_frame);
2003 n_left_from = from_frame->n_vectors;
2005 next_index = node->cached_next_index;
2007 int insert_pkts = 0, bsid_pkts = 0;
2009 while (n_left_from > 0)
2013 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2016 while (n_left_from >= 8 && n_left_to_next >= 4)
2018 u32 bi0, bi1, bi2, bi3;
2019 vlib_buffer_t *b0, *b1, *b2, *b3;
2020 u32 next0, next1, next2, next3;
2021 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2022 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2023 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2024 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2025 u16 new_l0, new_l1, new_l2, new_l3;
2027 /* Prefetch next iteration. */
2029 vlib_buffer_t *p4, *p5, *p6, *p7;
2031 p4 = vlib_get_buffer (vm, from[4]);
2032 p5 = vlib_get_buffer (vm, from[5]);
2033 p6 = vlib_get_buffer (vm, from[6]);
2034 p7 = vlib_get_buffer (vm, from[7]);
2036 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2037 vlib_prefetch_buffer_header (p4, LOAD);
2038 vlib_prefetch_buffer_header (p5, LOAD);
2039 vlib_prefetch_buffer_header (p6, LOAD);
2040 vlib_prefetch_buffer_header (p7, LOAD);
2042 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2043 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2044 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2045 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2048 to_next[0] = bi0 = from[0];
2049 to_next[1] = bi1 = from[1];
2050 to_next[2] = bi2 = from[2];
2051 to_next[3] = bi3 = from[3];
2055 n_left_to_next -= 4;
2057 b0 = vlib_get_buffer (vm, bi0);
2058 b1 = vlib_get_buffer (vm, bi1);
2059 b2 = vlib_get_buffer (vm, bi2);
2060 b3 = vlib_get_buffer (vm, bi3);
2063 pool_elt_at_index (sm->sid_lists,
2064 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2066 pool_elt_at_index (sm->sid_lists,
2067 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2069 pool_elt_at_index (sm->sid_lists,
2070 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2072 pool_elt_at_index (sm->sid_lists,
2073 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2074 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2075 vec_len (sl0->rewrite));
2076 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2077 vec_len (sl1->rewrite));
2078 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2079 vec_len (sl2->rewrite));
2080 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2081 vec_len (sl3->rewrite));
2083 ip0 = vlib_buffer_get_current (b0);
2084 ip1 = vlib_buffer_get_current (b1);
2085 ip2 = vlib_buffer_get_current (b2);
2086 ip3 = vlib_buffer_get_current (b3);
2088 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2090 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2091 ip6_ext_header_len (ip0 + 1));
2093 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2095 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2097 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2098 ip6_ext_header_len (ip1 + 1));
2100 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2102 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2104 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2105 ip6_ext_header_len (ip2 + 1));
2107 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2109 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2111 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2112 ip6_ext_header_len (ip3 + 1));
2114 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2116 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2117 (void *) sr0 - (void *) ip0);
2118 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2119 (void *) sr1 - (void *) ip1);
2120 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2121 (void *) sr2 - (void *) ip2);
2122 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2123 (void *) sr3 - (void *) ip3);
2125 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2126 vec_len (sl0->rewrite));
2127 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2128 vec_len (sl1->rewrite));
2129 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2130 vec_len (sl2->rewrite));
2131 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2132 vec_len (sl3->rewrite));
2134 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2135 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2136 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2137 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2139 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2140 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2141 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2142 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2144 ip0->hop_limit -= 1;
2145 ip1->hop_limit -= 1;
2146 ip2->hop_limit -= 1;
2147 ip3->hop_limit -= 1;
2150 clib_net_to_host_u16 (ip0->payload_length) +
2151 vec_len (sl0->rewrite);
2153 clib_net_to_host_u16 (ip1->payload_length) +
2154 vec_len (sl1->rewrite);
2156 clib_net_to_host_u16 (ip2->payload_length) +
2157 vec_len (sl2->rewrite);
2159 clib_net_to_host_u16 (ip3->payload_length) +
2160 vec_len (sl3->rewrite);
2162 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2163 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2164 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2165 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2167 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2168 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2169 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2170 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2172 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2173 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2174 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2175 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2176 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2177 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2178 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2179 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2181 ip0->dst_address.as_u64[0] =
2182 (sr0->segments + sr0->segments_left)->as_u64[0];
2183 ip0->dst_address.as_u64[1] =
2184 (sr0->segments + sr0->segments_left)->as_u64[1];
2185 ip1->dst_address.as_u64[0] =
2186 (sr1->segments + sr1->segments_left)->as_u64[0];
2187 ip1->dst_address.as_u64[1] =
2188 (sr1->segments + sr1->segments_left)->as_u64[1];
2189 ip2->dst_address.as_u64[0] =
2190 (sr2->segments + sr2->segments_left)->as_u64[0];
2191 ip2->dst_address.as_u64[1] =
2192 (sr2->segments + sr2->segments_left)->as_u64[1];
2193 ip3->dst_address.as_u64[0] =
2194 (sr3->segments + sr3->segments_left)->as_u64[0];
2195 ip3->dst_address.as_u64[1] =
2196 (sr3->segments + sr3->segments_left)->as_u64[1];
2198 ip6_ext_header_t *ip_ext;
2199 if (ip0 + 1 == (void *) sr0)
2201 sr0->protocol = ip0->protocol;
2202 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2206 ip_ext = (void *) (ip0 + 1);
2207 sr0->protocol = ip_ext->next_hdr;
2208 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2211 if (ip1 + 1 == (void *) sr1)
2213 sr1->protocol = ip1->protocol;
2214 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2218 ip_ext = (void *) (ip2 + 1);
2219 sr2->protocol = ip_ext->next_hdr;
2220 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2223 if (ip2 + 1 == (void *) sr2)
2225 sr2->protocol = ip2->protocol;
2226 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2230 ip_ext = (void *) (ip2 + 1);
2231 sr2->protocol = ip_ext->next_hdr;
2232 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2235 if (ip3 + 1 == (void *) sr3)
2237 sr3->protocol = ip3->protocol;
2238 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2242 ip_ext = (void *) (ip3 + 1);
2243 sr3->protocol = ip_ext->next_hdr;
2244 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2249 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2251 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2253 sr_policy_rewrite_trace_t *tr =
2254 vlib_add_trace (vm, node, b0, sizeof (*tr));
2255 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2256 sizeof (tr->src.as_u8));
2257 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2258 sizeof (tr->dst.as_u8));
2261 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2263 sr_policy_rewrite_trace_t *tr =
2264 vlib_add_trace (vm, node, b1, sizeof (*tr));
2265 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2266 sizeof (tr->src.as_u8));
2267 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2268 sizeof (tr->dst.as_u8));
2271 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2273 sr_policy_rewrite_trace_t *tr =
2274 vlib_add_trace (vm, node, b2, sizeof (*tr));
2275 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2276 sizeof (tr->src.as_u8));
2277 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2278 sizeof (tr->dst.as_u8));
2281 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2283 sr_policy_rewrite_trace_t *tr =
2284 vlib_add_trace (vm, node, b3, sizeof (*tr));
2285 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2286 sizeof (tr->src.as_u8));
2287 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2288 sizeof (tr->dst.as_u8));
2292 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2293 n_left_to_next, bi0, bi1, bi2, bi3,
2294 next0, next1, next2, next3);
2297 /* Single loop for potentially the last three packets */
2298 while (n_left_from > 0 && n_left_to_next > 0)
2302 ip6_header_t *ip0 = 0;
2303 ip6_sr_header_t *sr0 = 0;
2305 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2313 n_left_to_next -= 1;
2315 b0 = vlib_get_buffer (vm, bi0);
2317 pool_elt_at_index (sm->sid_lists,
2318 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2319 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2320 vec_len (sl0->rewrite));
2322 ip0 = vlib_buffer_get_current (b0);
2324 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2326 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2327 ip6_ext_header_len (ip0 + 1));
2329 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2331 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2332 (void *) sr0 - (void *) ip0);
2333 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2334 vec_len (sl0->rewrite));
2336 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2338 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2339 ip0->hop_limit -= 1;
2341 clib_net_to_host_u16 (ip0->payload_length) +
2342 vec_len (sl0->rewrite);
2343 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2345 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2346 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2347 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2349 ip0->dst_address.as_u64[0] =
2350 (sr0->segments + sr0->segments_left)->as_u64[0];
2351 ip0->dst_address.as_u64[1] =
2352 (sr0->segments + sr0->segments_left)->as_u64[1];
2354 if (ip0 + 1 == (void *) sr0)
2356 sr0->protocol = ip0->protocol;
2357 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2361 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2362 sr0->protocol = ip_ext->next_hdr;
2363 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2366 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2367 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2369 sr_policy_rewrite_trace_t *tr =
2370 vlib_add_trace (vm, node, b0, sizeof (*tr));
2371 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2372 sizeof (tr->src.as_u8));
2373 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2374 sizeof (tr->dst.as_u8));
2379 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2380 n_left_to_next, bi0, next0);
2383 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2386 /* Update counters */
2387 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2388 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2390 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2391 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2393 return from_frame->n_vectors;
2397 VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2398 .function = sr_policy_rewrite_insert,
2399 .name = "sr-pl-rewrite-insert",
2400 .vector_size = sizeof (u32),
2401 .format_trace = format_sr_policy_rewrite_trace,
2402 .type = VLIB_NODE_TYPE_INTERNAL,
2403 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2404 .error_strings = sr_policy_rewrite_error_strings,
2405 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2407 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2408 foreach_sr_policy_rewrite_next
2415 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2418 sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2419 vlib_frame_t * from_frame)
2421 ip6_sr_main_t *sm = &sr_main;
2422 u32 n_left_from, next_index, *from, *to_next;
2424 from = vlib_frame_vector_args (from_frame);
2425 n_left_from = from_frame->n_vectors;
2427 next_index = node->cached_next_index;
2429 int insert_pkts = 0, bsid_pkts = 0;
2431 while (n_left_from > 0)
2435 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2438 while (n_left_from >= 8 && n_left_to_next >= 4)
2440 u32 bi0, bi1, bi2, bi3;
2441 vlib_buffer_t *b0, *b1, *b2, *b3;
2442 u32 next0, next1, next2, next3;
2443 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2444 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2445 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2446 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2447 u16 new_l0, new_l1, new_l2, new_l3;
2449 /* Prefetch next iteration. */
2451 vlib_buffer_t *p4, *p5, *p6, *p7;
2453 p4 = vlib_get_buffer (vm, from[4]);
2454 p5 = vlib_get_buffer (vm, from[5]);
2455 p6 = vlib_get_buffer (vm, from[6]);
2456 p7 = vlib_get_buffer (vm, from[7]);
2458 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2459 vlib_prefetch_buffer_header (p4, LOAD);
2460 vlib_prefetch_buffer_header (p5, LOAD);
2461 vlib_prefetch_buffer_header (p6, LOAD);
2462 vlib_prefetch_buffer_header (p7, LOAD);
2464 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2465 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2466 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2467 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2470 to_next[0] = bi0 = from[0];
2471 to_next[1] = bi1 = from[1];
2472 to_next[2] = bi2 = from[2];
2473 to_next[3] = bi3 = from[3];
2477 n_left_to_next -= 4;
2479 b0 = vlib_get_buffer (vm, bi0);
2480 b1 = vlib_get_buffer (vm, bi1);
2481 b2 = vlib_get_buffer (vm, bi2);
2482 b3 = vlib_get_buffer (vm, bi3);
2485 pool_elt_at_index (sm->sid_lists,
2486 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2488 pool_elt_at_index (sm->sid_lists,
2489 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2491 pool_elt_at_index (sm->sid_lists,
2492 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2494 pool_elt_at_index (sm->sid_lists,
2495 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2496 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2497 vec_len (sl0->rewrite_bsid));
2498 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2499 vec_len (sl1->rewrite_bsid));
2500 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2501 vec_len (sl2->rewrite_bsid));
2502 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2503 vec_len (sl3->rewrite_bsid));
2505 ip0 = vlib_buffer_get_current (b0);
2506 ip1 = vlib_buffer_get_current (b1);
2507 ip2 = vlib_buffer_get_current (b2);
2508 ip3 = vlib_buffer_get_current (b3);
2510 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2512 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2513 ip6_ext_header_len (ip0 + 1));
2515 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2517 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2519 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2520 ip6_ext_header_len (ip1 + 1));
2522 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2524 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2526 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2527 ip6_ext_header_len (ip2 + 1));
2529 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2531 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2533 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2534 ip6_ext_header_len (ip3 + 1));
2536 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2538 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2539 (void *) sr0 - (void *) ip0);
2540 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2541 (void *) sr1 - (void *) ip1);
2542 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2543 (void *) sr2 - (void *) ip2);
2544 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2545 (void *) sr3 - (void *) ip3);
2547 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2548 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2549 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2550 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2551 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2552 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2553 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2554 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2556 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2557 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2558 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2559 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2561 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2562 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2563 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2564 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2566 ip0->hop_limit -= 1;
2567 ip1->hop_limit -= 1;
2568 ip2->hop_limit -= 1;
2569 ip3->hop_limit -= 1;
2572 clib_net_to_host_u16 (ip0->payload_length) +
2573 vec_len (sl0->rewrite_bsid);
2575 clib_net_to_host_u16 (ip1->payload_length) +
2576 vec_len (sl1->rewrite_bsid);
2578 clib_net_to_host_u16 (ip2->payload_length) +
2579 vec_len (sl2->rewrite_bsid);
2581 clib_net_to_host_u16 (ip3->payload_length) +
2582 vec_len (sl3->rewrite_bsid);
2584 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2585 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2586 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2587 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2589 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2590 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2591 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2592 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2594 ip0->dst_address.as_u64[0] =
2595 (sr0->segments + sr0->segments_left)->as_u64[0];
2596 ip0->dst_address.as_u64[1] =
2597 (sr0->segments + sr0->segments_left)->as_u64[1];
2598 ip1->dst_address.as_u64[0] =
2599 (sr1->segments + sr1->segments_left)->as_u64[0];
2600 ip1->dst_address.as_u64[1] =
2601 (sr1->segments + sr1->segments_left)->as_u64[1];
2602 ip2->dst_address.as_u64[0] =
2603 (sr2->segments + sr2->segments_left)->as_u64[0];
2604 ip2->dst_address.as_u64[1] =
2605 (sr2->segments + sr2->segments_left)->as_u64[1];
2606 ip3->dst_address.as_u64[0] =
2607 (sr3->segments + sr3->segments_left)->as_u64[0];
2608 ip3->dst_address.as_u64[1] =
2609 (sr3->segments + sr3->segments_left)->as_u64[1];
2611 ip6_ext_header_t *ip_ext;
2612 if (ip0 + 1 == (void *) sr0)
2614 sr0->protocol = ip0->protocol;
2615 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2619 ip_ext = (void *) (ip0 + 1);
2620 sr0->protocol = ip_ext->next_hdr;
2621 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2624 if (ip1 + 1 == (void *) sr1)
2626 sr1->protocol = ip1->protocol;
2627 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2631 ip_ext = (void *) (ip2 + 1);
2632 sr2->protocol = ip_ext->next_hdr;
2633 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2636 if (ip2 + 1 == (void *) sr2)
2638 sr2->protocol = ip2->protocol;
2639 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2643 ip_ext = (void *) (ip2 + 1);
2644 sr2->protocol = ip_ext->next_hdr;
2645 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2648 if (ip3 + 1 == (void *) sr3)
2650 sr3->protocol = ip3->protocol;
2651 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2655 ip_ext = (void *) (ip3 + 1);
2656 sr3->protocol = ip_ext->next_hdr;
2657 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2662 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2664 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2666 sr_policy_rewrite_trace_t *tr =
2667 vlib_add_trace (vm, node, b0, sizeof (*tr));
2668 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2669 sizeof (tr->src.as_u8));
2670 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2671 sizeof (tr->dst.as_u8));
2674 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2676 sr_policy_rewrite_trace_t *tr =
2677 vlib_add_trace (vm, node, b1, sizeof (*tr));
2678 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2679 sizeof (tr->src.as_u8));
2680 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2681 sizeof (tr->dst.as_u8));
2684 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2686 sr_policy_rewrite_trace_t *tr =
2687 vlib_add_trace (vm, node, b2, sizeof (*tr));
2688 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2689 sizeof (tr->src.as_u8));
2690 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2691 sizeof (tr->dst.as_u8));
2694 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2696 sr_policy_rewrite_trace_t *tr =
2697 vlib_add_trace (vm, node, b3, sizeof (*tr));
2698 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2699 sizeof (tr->src.as_u8));
2700 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2701 sizeof (tr->dst.as_u8));
2705 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2706 n_left_to_next, bi0, bi1, bi2, bi3,
2707 next0, next1, next2, next3);
2710 /* Single loop for potentially the last three packets */
2711 while (n_left_from > 0 && n_left_to_next > 0)
2715 ip6_header_t *ip0 = 0;
2716 ip6_sr_header_t *sr0 = 0;
2718 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2726 n_left_to_next -= 1;
2728 b0 = vlib_get_buffer (vm, bi0);
2730 pool_elt_at_index (sm->sid_lists,
2731 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2732 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2733 vec_len (sl0->rewrite_bsid));
2735 ip0 = vlib_buffer_get_current (b0);
2737 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2739 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2740 ip6_ext_header_len (ip0 + 1));
2742 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2744 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2745 (void *) sr0 - (void *) ip0);
2746 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2747 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2749 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2751 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2752 ip0->hop_limit -= 1;
2754 clib_net_to_host_u16 (ip0->payload_length) +
2755 vec_len (sl0->rewrite_bsid);
2756 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2758 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2760 ip0->dst_address.as_u64[0] =
2761 (sr0->segments + sr0->segments_left)->as_u64[0];
2762 ip0->dst_address.as_u64[1] =
2763 (sr0->segments + sr0->segments_left)->as_u64[1];
2765 if (ip0 + 1 == (void *) sr0)
2767 sr0->protocol = ip0->protocol;
2768 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2772 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2773 sr0->protocol = ip_ext->next_hdr;
2774 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2777 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2778 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2780 sr_policy_rewrite_trace_t *tr =
2781 vlib_add_trace (vm, node, b0, sizeof (*tr));
2782 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2783 sizeof (tr->src.as_u8));
2784 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2785 sizeof (tr->dst.as_u8));
2790 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2791 n_left_to_next, bi0, next0);
2794 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2797 /* Update counters */
2798 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2799 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2801 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2802 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2804 return from_frame->n_vectors;
2808 VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2809 .function = sr_policy_rewrite_b_insert,
2810 .name = "sr-pl-rewrite-b-insert",
2811 .vector_size = sizeof (u32),
2812 .format_trace = format_sr_policy_rewrite_trace,
2813 .type = VLIB_NODE_TYPE_INTERNAL,
2814 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2815 .error_strings = sr_policy_rewrite_error_strings,
2816 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2818 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2819 foreach_sr_policy_rewrite_next
2826 * @brief Function BSID encapsulation
2828 static_always_inline void
2829 end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2832 ip6_sr_header_t * sr0, u32 * next0)
2834 ip6_address_t *new_dst0;
2836 if (PREDICT_FALSE (!sr0))
2837 goto error_bsid_encaps;
2839 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2841 if (PREDICT_TRUE (sr0->segments_left != 0))
2843 sr0->segments_left -= 1;
2844 new_dst0 = (ip6_address_t *) (sr0->segments);
2845 new_dst0 += sr0->segments_left;
2846 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2847 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2853 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2854 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2858 * @brief Graph node for applying a SR policy BSID - Encapsulation
2861 sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2862 vlib_frame_t * from_frame)
2864 ip6_sr_main_t *sm = &sr_main;
2865 u32 n_left_from, next_index, *from, *to_next;
2867 from = vlib_frame_vector_args (from_frame);
2868 n_left_from = from_frame->n_vectors;
2870 next_index = node->cached_next_index;
2872 int encap_pkts = 0, bsid_pkts = 0;
2874 while (n_left_from > 0)
2878 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2881 while (n_left_from >= 8 && n_left_to_next >= 4)
2883 u32 bi0, bi1, bi2, bi3;
2884 vlib_buffer_t *b0, *b1, *b2, *b3;
2885 u32 next0, next1, next2, next3;
2886 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2887 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2888 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2889 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2890 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2891 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2893 /* Prefetch next iteration. */
2895 vlib_buffer_t *p4, *p5, *p6, *p7;
2897 p4 = vlib_get_buffer (vm, from[4]);
2898 p5 = vlib_get_buffer (vm, from[5]);
2899 p6 = vlib_get_buffer (vm, from[6]);
2900 p7 = vlib_get_buffer (vm, from[7]);
2902 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2903 vlib_prefetch_buffer_header (p4, LOAD);
2904 vlib_prefetch_buffer_header (p5, LOAD);
2905 vlib_prefetch_buffer_header (p6, LOAD);
2906 vlib_prefetch_buffer_header (p7, LOAD);
2908 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2909 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2910 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2911 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2914 to_next[0] = bi0 = from[0];
2915 to_next[1] = bi1 = from[1];
2916 to_next[2] = bi2 = from[2];
2917 to_next[3] = bi3 = from[3];
2921 n_left_to_next -= 4;
2923 b0 = vlib_get_buffer (vm, bi0);
2924 b1 = vlib_get_buffer (vm, bi1);
2925 b2 = vlib_get_buffer (vm, bi2);
2926 b3 = vlib_get_buffer (vm, bi3);
2929 pool_elt_at_index (sm->sid_lists,
2930 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2932 pool_elt_at_index (sm->sid_lists,
2933 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2935 pool_elt_at_index (sm->sid_lists,
2936 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2938 pool_elt_at_index (sm->sid_lists,
2939 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2940 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2941 vec_len (sl0->rewrite));
2942 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2943 vec_len (sl1->rewrite));
2944 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2945 vec_len (sl2->rewrite));
2946 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2947 vec_len (sl3->rewrite));
2949 ip0_encap = vlib_buffer_get_current (b0);
2950 ip1_encap = vlib_buffer_get_current (b1);
2951 ip2_encap = vlib_buffer_get_current (b2);
2952 ip3_encap = vlib_buffer_get_current (b3);
2954 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2955 IP_PROTOCOL_IPV6_ROUTE);
2956 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2957 IP_PROTOCOL_IPV6_ROUTE);
2958 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2959 IP_PROTOCOL_IPV6_ROUTE);
2960 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2961 IP_PROTOCOL_IPV6_ROUTE);
2963 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2964 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2965 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2966 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2968 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2969 sl0->rewrite, vec_len (sl0->rewrite));
2970 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2971 sl1->rewrite, vec_len (sl1->rewrite));
2972 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2973 sl2->rewrite, vec_len (sl2->rewrite));
2974 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2975 sl3->rewrite, vec_len (sl3->rewrite));
2977 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2978 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2979 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2980 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2982 ip0 = vlib_buffer_get_current (b0);
2983 ip1 = vlib_buffer_get_current (b1);
2984 ip2 = vlib_buffer_get_current (b2);
2985 ip3 = vlib_buffer_get_current (b3);
2987 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2988 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2989 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2990 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2992 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2994 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2996 sr_policy_rewrite_trace_t *tr =
2997 vlib_add_trace (vm, node, b0, sizeof (*tr));
2998 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2999 sizeof (tr->src.as_u8));
3000 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3001 sizeof (tr->dst.as_u8));
3004 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3006 sr_policy_rewrite_trace_t *tr =
3007 vlib_add_trace (vm, node, b1, sizeof (*tr));
3008 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3009 sizeof (tr->src.as_u8));
3010 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3011 sizeof (tr->dst.as_u8));
3014 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3016 sr_policy_rewrite_trace_t *tr =
3017 vlib_add_trace (vm, node, b2, sizeof (*tr));
3018 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3019 sizeof (tr->src.as_u8));
3020 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3021 sizeof (tr->dst.as_u8));
3024 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3026 sr_policy_rewrite_trace_t *tr =
3027 vlib_add_trace (vm, node, b3, sizeof (*tr));
3028 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3029 sizeof (tr->src.as_u8));
3030 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3031 sizeof (tr->dst.as_u8));
3036 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3037 n_left_to_next, bi0, bi1, bi2, bi3,
3038 next0, next1, next2, next3);
3041 /* Single loop for potentially the last three packets */
3042 while (n_left_from > 0 && n_left_to_next > 0)
3046 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3047 ip6_ext_header_t *prev0;
3048 ip6_sr_header_t *sr0;
3050 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3057 n_left_to_next -= 1;
3058 b0 = vlib_get_buffer (vm, bi0);
3061 pool_elt_at_index (sm->sid_lists,
3062 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3063 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3064 vec_len (sl0->rewrite));
3066 ip0_encap = vlib_buffer_get_current (b0);
3067 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3068 IP_PROTOCOL_IPV6_ROUTE);
3069 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3071 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3072 sl0->rewrite, vec_len (sl0->rewrite));
3073 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3075 ip0 = vlib_buffer_get_current (b0);
3077 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3079 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3080 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3082 sr_policy_rewrite_trace_t *tr =
3083 vlib_add_trace (vm, node, b0, sizeof (*tr));
3084 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3085 sizeof (tr->src.as_u8));
3086 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3087 sizeof (tr->dst.as_u8));
3091 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3092 n_left_to_next, bi0, next0);
3095 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3098 /* Update counters */
3099 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3100 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3102 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3103 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3106 return from_frame->n_vectors;
3110 VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3111 .function = sr_policy_rewrite_b_encaps,
3112 .name = "sr-pl-rewrite-b-encaps",
3113 .vector_size = sizeof (u32),
3114 .format_trace = format_sr_policy_rewrite_trace,
3115 .type = VLIB_NODE_TYPE_INTERNAL,
3116 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3117 .error_strings = sr_policy_rewrite_error_strings,
3118 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3120 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3121 foreach_sr_policy_rewrite_next
3127 /*************************** SR Segment Lists DPOs ****************************/
3129 format_sr_segment_list_dpo (u8 * s, va_list * args)
3131 ip6_sr_main_t *sm = &sr_main;
3132 ip6_address_t *addr;
3135 index_t index = va_arg (*args, index_t);
3136 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3137 s = format (s, "SR: Segment List index:[%d]", index);
3138 s = format (s, "\n\tSegments:");
3140 sl = pool_elt_at_index (sm->sid_lists, index);
3142 s = format (s, "< ");
3143 vec_foreach (addr, sl->segments)
3145 s = format (s, "%U, ", format_ip6_address, addr);
3147 s = format (s, "\b\b > - ");
3148 s = format (s, "Weight: %u", sl->weight);
3153 const static dpo_vft_t sr_policy_rewrite_vft = {
3154 .dv_lock = sr_dpo_lock,
3155 .dv_unlock = sr_dpo_unlock,
3156 .dv_format = format_sr_segment_list_dpo,
3159 const static char *const sr_pr_encaps_ip6_nodes[] = {
3160 "sr-pl-rewrite-encaps",
3164 const static char *const sr_pr_encaps_ip4_nodes[] = {
3165 "sr-pl-rewrite-encaps-v4",
3169 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3170 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3171 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3174 const static char *const sr_pr_insert_ip6_nodes[] = {
3175 "sr-pl-rewrite-insert",
3179 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3180 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3183 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3184 "sr-pl-rewrite-b-insert",
3188 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3189 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3192 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3193 "sr-pl-rewrite-b-encaps",
3197 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3198 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3201 /********************* SR Policy Rewrite initialization ***********************/
3203 * @brief SR Policy Rewrite initialization
3206 sr_policy_rewrite_init (vlib_main_t * vm)
3208 ip6_sr_main_t *sm = &sr_main;
3210 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3211 sm->sr_policy_index_by_key = hash_create_mem (0, sizeof (ip6_address_t),
3214 /* Init SR VPO DPOs type */
3215 sr_pr_encaps_dpo_type =
3216 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3218 sr_pr_insert_dpo_type =
3219 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3221 sr_pr_bsid_encaps_dpo_type =
3222 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3224 sr_pr_bsid_insert_dpo_type =
3225 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3227 /* Register the L2 encaps node used in HW redirect */
3228 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3230 sm->fib_table_ip6 = (u32) ~ 0;
3231 sm->fib_table_ip4 = (u32) ~ 0;
3236 VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3240 * fd.io coding-style-patch-verification: ON
3243 * eval: (c-set-style "gnu")