blob: 1f8bdca51438a7e4fba133c7d0dcbbd69de99492 [file] [log] [blame]
Pablo Camarillofb380952016-12-07 18:34:18 +01001/*
2 * sr_policy_rewrite.c: ipv6 sr policy creation
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18/**
19 * @file
20 * @brief SR policy creation and application
21 *
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.
29 *
30 * SR policies can be applied either by using IPv6 encapsulation or
31 * SRH insertion. Both methods can be found on this file.
32 *
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)
35 *
36 * This file provides the appropiates VPP graph nodes to do any of these
37 * methods.
38 *
39 */
40
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>
50
51#include <vppinfra/error.h>
52#include <vppinfra/elog.h>
53
54/**
55 * @brief SR policy rewrite trace
56 */
57typedef struct
58{
59 ip6_address_t src, dst;
60} sr_policy_rewrite_trace_t;
61
62/* Graph arcs */
63#define foreach_sr_policy_rewrite_next \
64_(IP6_LOOKUP, "ip6-lookup") \
65_(ERROR, "error-drop")
66
67typedef enum
68{
69#define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
70 foreach_sr_policy_rewrite_next
71#undef _
72 SR_POLICY_REWRITE_N_NEXT,
73} sr_policy_rewrite_next_t;
74
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")
83
84typedef enum
85{
86#define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
87 foreach_sr_policy_rewrite_error
88#undef _
89 SR_POLICY_REWRITE_N_ERROR,
90} sr_policy_rewrite_error_t;
91
92static char *sr_policy_rewrite_error_strings[] = {
93#define _(sym,string) string,
94 foreach_sr_policy_rewrite_error
95#undef _
96};
97
98/**
99 * @brief Dynamically added SR SL DPO type
100 */
101static dpo_type_t sr_pr_encaps_dpo_type;
102static dpo_type_t sr_pr_insert_dpo_type;
103static dpo_type_t sr_pr_bsid_encaps_dpo_type;
104static dpo_type_t sr_pr_bsid_insert_dpo_type;
105
106/**
107 * @brief IPv6 SA for encapsulated packets
108 */
109static ip6_address_t sr_pr_encaps_src;
110
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 */
114
115static clib_error_t *
116set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
117 vlib_cli_command_t * cmd)
118{
119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
120 {
121 if (unformat
122 (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
123 return 0;
124 else
125 return clib_error_return (0, "No address specified");
126 }
127 return clib_error_return (0, "No address specified");
128}
129
130/* *INDENT-OFF* */
131VLIB_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,
135};
136/* *INDENT-ON* */
137
138/*********************** SR rewrite string computation ************************/
139/**
140 * @brief SR rewrite string computation for IPv6 encapsulation (inline)
141 *
142 * @param sl is a vector of IPv6 addresses composing the Segment List
143 *
144 * @return precomputed rewrite string for encapsulation
145 */
146static inline u8 *
147compute_rewrite_encaps (ip6_address_t * sl)
148{
149 ip6_header_t *iph;
150 ip6_sr_header_t *srh;
151 ip6_address_t *addrp, *this_address;
152 u32 header_length = 0;
153 u8 *rs = NULL;
154
155 header_length = 0;
156 header_length += IPv6_DEFAULT_HEADER_LENGTH;
157 if (vec_len (sl) > 1)
158 {
159 header_length += sizeof (ip6_sr_header_t);
160 header_length += vec_len (sl) * sizeof (ip6_address_t);
161 }
162
163 vec_validate (rs, header_length - 1);
164
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;
173
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;
182 srh->flags = 0x00;
183 srh->reserved = 0x00;
184 addrp = srh->segments + vec_len (sl) - 1;
185 vec_foreach (this_address, sl)
186 {
187 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
188 addrp--;
189 }
190 iph->dst_address.as_u64[0] = sl->as_u64[0];
191 iph->dst_address.as_u64[1] = sl->as_u64[1];
192 return rs;
193}
194
195/**
196 * @brief SR rewrite string computation for SRH insertion (inline)
197 *
198 * @param sl is a vector of IPv6 addresses composing the Segment List
199 *
200 * @return precomputed rewrite string for SRH insertion
201 */
202static inline u8 *
203compute_rewrite_insert (ip6_address_t * sl)
204{
205 ip6_sr_header_t *srh;
206 ip6_address_t *addrp, *this_address;
207 u32 header_length = 0;
208 u8 *rs = NULL;
209
210 header_length = 0;
211 header_length += sizeof (ip6_sr_header_t);
212 header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
213
214 vec_validate (rs, header_length - 1);
215
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;
222 srh->flags = 0x00;
223 srh->reserved = 0x0000;
224 addrp = srh->segments + vec_len (sl);
225 vec_foreach (this_address, sl)
226 {
227 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
228 addrp--;
229 }
230 return rs;
231}
232
233/**
234 * @brief SR rewrite string computation for SRH insertion with BSID (inline)
235 *
236 * @param sl is a vector of IPv6 addresses composing the Segment List
237 *
238 * @return precomputed rewrite string for SRH insertion with BSID
239 */
240static inline u8 *
241compute_rewrite_bsid (ip6_address_t * sl)
242{
243 ip6_sr_header_t *srh;
244 ip6_address_t *addrp, *this_address;
245 u32 header_length = 0;
246 u8 *rs = NULL;
247
248 header_length = 0;
249 header_length += sizeof (ip6_sr_header_t);
250 header_length += vec_len (sl) * sizeof (ip6_address_t);
251
252 vec_validate (rs, header_length - 1);
253
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;
260 srh->flags = 0x00;
261 srh->reserved = 0x0000;
262 addrp = srh->segments + vec_len (sl) - 1;
263 vec_foreach (this_address, sl)
264 {
265 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
266 addrp--;
267 }
268 return rs;
269}
270
271/*************************** SR LB helper functions **************************/
272/**
273 * @brief Creates a Segment List and adds it to an SR policy
274 *
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.
278 *
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)
283 *
284 * @return pointer to the just created segment list
285 */
286static inline ip6_sr_sl_t *
287create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
288 u8 is_encap)
289{
290 ip6_sr_main_t *sm = &sr_main;
291 ip6_sr_sl_t *segment_list;
292
293 pool_get (sm->sid_lists, segment_list);
294 memset (segment_list, 0, sizeof (*segment_list));
295
296 vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
297
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);
302
303 if (is_encap)
304 {
305 segment_list->rewrite = compute_rewrite_encaps (sl);
306 segment_list->rewrite_bsid = segment_list->rewrite;
307 }
308 else
309 {
310 segment_list->rewrite = compute_rewrite_insert (sl);
311 segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
312 }
313
314 /* Create DPO */
315 dpo_reset (&segment_list->bsid_dpo);
316 dpo_reset (&segment_list->ip6_dpo);
317 dpo_reset (&segment_list->ip4_dpo);
318
319 if (is_encap)
320 {
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);
327 }
328 else
329 {
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);
334 }
335
336 return segment_list;
337}
338
339/**
340 * @brief Updates the Load Balancer after an SR Policy change
341 *
342 * @param sr_policy is the modified SR Policy
343 */
344static inline void
345update_lb (ip6_sr_policy_t * sr_policy)
346{
347 flow_hash_config_t fhc;
348 u32 *sl_index;
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;
355
356 /* In case LB does not exist, create it */
357 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
358 {
359 fib_prefix_t pfx = {
360 .fp_proto = FIB_PROTOCOL_IP6,
361 .fp_len = 128,
362 .fp_addr = {
363 .ip6 = sr_policy->bsid,
364 }
365 };
366
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));
370
371 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
372 load_balance_create (0, DPO_PROTO_IP6, fhc));
373
374 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
375 load_balance_create (0, DPO_PROTO_IP6, fhc));
376
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
379 (FIB_PROTOCOL_IP6,
380 sr_policy->fib_table), &pfx,
381 FIB_SOURCE_SR,
382 FIB_ENTRY_FLAG_EXCLUSIVE,
383 &sr_policy->bsid_dpo);
384
385 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
386 &pfx,
387 FIB_SOURCE_SR,
388 FIB_ENTRY_FLAG_EXCLUSIVE,
389 &sr_policy->ip6_dpo);
390
391 if (sr_policy->is_encap)
392 {
393 dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
394 load_balance_create (0, DPO_PROTO_IP4, fhc));
395
396 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
397 &pfx,
398 FIB_SOURCE_SR,
399 FIB_ENTRY_FLAG_EXCLUSIVE,
400 &sr_policy->ip4_dpo);
401 }
402
403 }
404
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)
408 {
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)
416 {
417 path.path_dpo = segment_list->ip4_dpo;
418 vec_add1 (ip4_path_vector, path);
419 }
420 }
421
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);
430
431 /* Cleanup */
432 vec_free (b_path_vector);
433 vec_free (ip6_path_vector);
434 vec_free (ip4_path_vector);
435
436}
437
438/**
439 * @brief Updates the Replicate DPO after an SR Policy change
440 *
441 * @param sr_policy is the modified SR Policy (type spray)
442 */
443static inline void
444update_replicate (ip6_sr_policy_t * sr_policy)
445{
446 u32 *sl_index;
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;
453
454 /* In case LB does not exist, create it */
455 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
456 {
457 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
458 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
459
460 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
461 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
462
463 /* Update FIB entry's DPO to point to SR without LB */
464 fib_prefix_t pfx = {
465 .fp_proto = FIB_PROTOCOL_IP6,
466 .fp_len = 128,
467 .fp_addr = {
468 .ip6 = sr_policy->bsid,
469 }
470 };
471 fib_table_entry_special_dpo_update (fib_table_id_find_fib_index
472 (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table), &pfx,
474 FIB_SOURCE_SR,
475 FIB_ENTRY_FLAG_EXCLUSIVE,
476 &sr_policy->bsid_dpo);
477
478 fib_table_entry_special_dpo_update (sm->fib_table_ip6,
479 &pfx,
480 FIB_SOURCE_SR,
481 FIB_ENTRY_FLAG_EXCLUSIVE,
482 &sr_policy->ip6_dpo);
483
484 if (sr_policy->is_encap)
485 {
486 dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
487 replicate_create (0, DPO_PROTO_IP4));
488
489 fib_table_entry_special_dpo_update (sm->fib_table_ip4,
490 &pfx,
491 FIB_SOURCE_SR,
492 FIB_ENTRY_FLAG_EXCLUSIVE,
493 &sr_policy->ip4_dpo);
494 }
495
496 }
497
498 /* Create the replicate path vector */
499 path.path_weight = 1;
500 vec_foreach (sl_index, sr_policy->segments_lists)
501 {
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)
508 {
509 path.path_dpo = segment_list->ip4_dpo;
510 vec_add1 (ip4_path_vector, path);
511 }
512 }
513
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);
519
520 /* Cleanup */
521 vec_free (b_path_vector);
522 vec_free (ip6_path_vector);
523 vec_free (ip4_path_vector);
524}
525
526/******************************* SR rewrite API *******************************/
527/* Three functions for handling sr policies:
528 * -> sr_policy_add
529 * -> sr_policy_del
530 * -> sr_policy_mod
531 * All of them are API. CLI function on sr_policy_command_fn */
532
533/**
534 * @brief Create a new SR policy
535 *
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
542 *
543 * @return 0 if correct, else error
544 */
545int
546sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
547 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
548{
549 ip6_sr_main_t *sm = &sr_main;
550 ip6_sr_policy_t *sr_policy = 0;
551 ip6_address_t *key_copy;
552 uword *p;
553
554 /* Search for existing keys (BSID) */
555 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
556 if (p)
557 {
558 /* Add SR policy that already exists; complain */
559 return -12;
560 }
561
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 */
566 fib_prefix_t pfx = {
567 .fp_proto = FIB_PROTOCOL_IP6,
568 .fp_len = 128,
569 .fp_addr = {
570 .ip6 = *bsid,
571 }
572 };
573
574 /* Lookup the FIB index associated to the table selected */
575 u32 fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6,
576 (fib_table !=
577 (u32) ~ 0 ? fib_table : 0));
578 if (fib_index == ~0)
579 return -13;
580
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
585
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;
593
594 /* Copy the key */
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);
599
600 /* Create a segment list and add the index to the SR policy */
601 create_sl (sr_policy, segments, weight, is_encap);
602
603 /* If FIB doesnt exist, create them */
604 if (sm->fib_table_ip6 == (u32) ~ 0)
605 {
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,
611 FIB_SOURCE_SPECIAL);
612 fib_table_flush (sm->fib_table_ip4, FIB_PROTOCOL_IP6,
613 FIB_SOURCE_SPECIAL);
614 }
615
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);
621 return 0;
622}
623
624/**
625 * @brief Delete a SR policy
626 *
627 * @param bsid is the bindingSID of the SR Policy
628 * @param index is the index of the SR policy
629 *
630 * @return 0 if correct, else error
631 */
632int
633sr_policy_del (ip6_address_t * bsid, u32 index)
634{
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;
639 u32 *sl_index;
640 uword *p;
641
642 hash_pair_t *hp;
643 if (bsid)
644 {
645 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
646 if (p)
647 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
648 else
649 return -1;
650 }
651 else
652 {
653 sr_policy = pool_elt_at_index (sm->sr_policies, index);
654 if (!sr_policy)
655 return -1;
656 }
657
658 /* Remove BindingSID FIB entry */
659 fib_prefix_t pfx = {
660 .fp_proto = FIB_PROTOCOL_IP6,
661 .fp_len = 128,
662 .fp_addr = {
663 .ip6 = sr_policy->bsid,
664 }
665 ,
666 };
667
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);
671
672 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
673
674 if (sr_policy->is_encap)
675 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
676
677 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
678 {
679 dpo_reset (&sr_policy->bsid_dpo);
680 dpo_reset (&sr_policy->ip4_dpo);
681 dpo_reset (&sr_policy->ip6_dpo);
682 }
683
684 /* Clean SID Lists */
685 vec_foreach (sl_index, sr_policy->segments_lists)
686 {
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);
692 }
693
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);
698 vec_free (key_copy);
699 pool_put (sm->sr_policies, sr_policy);
700
701 /* If FIB empty unlock it */
702 if (!pool_elts (sm->sr_policies))
703 {
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;
708 }
709
710 return 0;
711}
712
713/**
714 * @brief Modify an existing SR policy
715 *
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.
719 *
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.
728 *
729 * @return 0 if correct, else error
730 */
731int
732sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
733 u8 operation, ip6_address_t * segments, u32 sl_index,
734 u32 weight)
735{
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;
740 uword *p;
741
742 if (bsid)
743 {
744 p = hash_get_mem (sm->sr_policy_index_by_key, bsid);
745 if (p)
746 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
747 else
748 return -1;
749 }
750 else
751 {
752 sr_policy = pool_elt_at_index (sm->sr_policies, index);
753 if (!sr_policy)
754 return -1;
755 }
756
757 if (operation == 1) /* Add SR List to an existing SR policy */
758 {
759 /* Create the new SL */
760 segment_list =
761 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
762
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);
768 }
769 else if (operation == 2) /* Delete SR List from an existing SR policy */
770 {
771 /* Check that currently there are more than one SID list */
772 if (vec_len (sr_policy->segments_lists) == 1)
773 return -21;
774
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)
778 break;
779
780 if (*sl_index_iterate != sl_index)
781 return -22;
782
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);
791
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);
797 }
798 else if (operation == 3) /* Modify the weight of an existing SR List */
799 {
800 /* Find the corresponding SL */
801 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
802 if (*sl_index_iterate == sl_index)
803 break;
804
805 if (*sl_index_iterate != sl_index)
806 return -32;
807
808 /* Change the weight */
809 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
810 segment_list->weight = weight;
811
812 /* Update LB */
813 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
814 update_lb (sr_policy);
815 }
816 else /* Incorrect op. */
817 return -1;
818
819 return 0;
820}
821
822/**
823 * @brief CLI for 'sr policies' command family
824 */
825static clib_error_t *
826sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
827 vlib_cli_command_t * cmd)
828{
829 int rv = -1;
830 char is_del = 0, is_add = 0, is_mod = 0;
831 char policy_set = 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;
836 u8 operation = 0;
837 char is_encap = 1;
838 char is_spray = 0;
839
840 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
841 {
842 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
843 is_add = 1;
844 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
845 is_del = 1;
846 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
847 is_mod = 1;
848 else if (!policy_set
849 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
850 policy_set = 1;
851 else if (!is_add && !policy_set
852 && unformat (input, "index %d", &sr_policy_index))
853 policy_set = 1;
854 else if (unformat (input, "weight %d", &weight));
855 else
856 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
857 {
858 vec_add2 (segments, this_seg, 1);
859 clib_memcpy (this_seg->as_u8, next_address.as_u8,
860 sizeof (*this_seg));
861 }
862 else if (unformat (input, "add sl"))
863 operation = 1;
864 else if (unformat (input, "del sl index %d", &sl_index))
865 operation = 2;
866 else if (unformat (input, "mod sl index %d", &sl_index))
867 operation = 3;
868 else if (fib_table == (u32) ~ 0
869 && unformat (input, "fib-table %d", &fib_table));
870 else if (unformat (input, "encap"))
871 is_encap = 1;
872 else if (unformat (input, "insert"))
873 is_encap = 0;
874 else if (unformat (input, "spray"))
875 is_spray = 1;
876 else
877 break;
878 }
879
880 if (!is_add && !is_mod && !is_del)
881 return clib_error_return (0, "Incorrect CLI");
882
883 if (!policy_set)
884 return clib_error_return (0, "No SR policy BSID or index specified");
885
886 if (is_add)
887 {
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);
893 }
894 else if (is_del)
895 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
896 sr_policy_index);
897 else if (is_mod)
898 {
899 if (!operation)
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,
909 sl_index, weight);
910 }
911
912 switch (rv)
913 {
914 case 0:
915 break;
916 case 1:
917 return 0;
918 case -12:
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.");
922 case -13:
923 return clib_error_return (0, "The specified FIB table does not exist.");
924 case -21:
925 return clib_error_return (0,
926 "The selected SR policy only contains ONE segment list. "
927 "Please remove the SR policy instead");
928 case -22:
929 return clib_error_return (0,
930 "Could not delete the segment list. "
931 "It is not associated with that SR policy.");
932 case -32:
933 return clib_error_return (0,
934 "Could not modify the segment list. "
935 "The given SL is not associated with such SR policy.");
936 default:
937 return clib_error_return (0, "BUG: sr policy returns %d", rv);
938 }
939 return 0;
940}
941
942/* *INDENT-OFF* */
943VLIB_CLI_COMMAND (sr_policy_command, static) = {
944 .path = "sr policy",
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)",
947 .long_help =
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"
959 "SID lists.\n",
960 .function = sr_policy_command_fn,
961};
962/* *INDENT-ON* */
963
964/**
965 * @brief CLI to display onscreen all the SR policies
966 */
967static clib_error_t *
968show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
969 vlib_cli_command_t * cmd)
970{
971 ip6_sr_main_t *sm = &sr_main;
972 u32 *sl_index;
973 ip6_sr_sl_t *segment_list = 0;
974 ip6_sr_policy_t *sr_policy = 0;
975 ip6_sr_policy_t **vec_policies = 0;
976 ip6_address_t *addr;
977 u8 *s;
978 int i = 0;
979
980 vlib_cli_output (vm, "SR policies:");
981
982 /* *INDENT-OFF* */
983 pool_foreach (sr_policy, sm->sr_policies,
984 {vec_add1 (vec_policies, sr_policy); } );
985 /* *INDENT-ON* */
986
987 vec_foreach_index (i, vec_policies)
988 {
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" :
995 "SRH insertion"));
996 vlib_cli_output (vm, "\tType: %s",
997 (sr_policy->type ==
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)
1004 {
1005 s = NULL;
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)
1010 {
1011 s = format (s, "%U, ", format_ip6_address, addr);
1012 }
1013 s = format (s, "\b\b > ");
1014 s = format (s, "weight: %u", segment_list->weight);
1015 vlib_cli_output (vm, " %s", s);
1016 }
1017 vlib_cli_output (vm, "-----------");
1018 }
1019 return 0;
1020}
1021
1022/* *INDENT-OFF* */
1023VLIB_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,
1027};
1028/* *INDENT-ON* */
1029
1030/*************************** SR rewrite graph node ****************************/
1031/**
1032 * @brief Trace for the SR Policy Rewrite graph node
1033 */
1034static u8 *
1035format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1036{
1037 //TODO
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 *);
1041
1042 s = format
1043 (s, "SR-policy-rewrite: src %U dst %U",
1044 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1045
1046 return s;
1047}
1048
1049/**
1050 * @brief IPv6 encapsulation processing as per RFC2473
1051 */
1052static_always_inline void
1053encaps_processing_v6 (vlib_node_runtime_t * node,
1054 vlib_buffer_t * b0,
1055 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1056{
1057 u32 new_l0;
1058
1059 ip0_encap->hop_limit -= 1;
1060 new_l0 =
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;
1066}
1067
1068/**
1069 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1070 */
1071static uword
1072sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1073 vlib_frame_t * from_frame)
1074{
1075 ip6_sr_main_t *sm = &sr_main;
1076 u32 n_left_from, next_index, *from, *to_next;
1077
1078 from = vlib_frame_vector_args (from_frame);
1079 n_left_from = from_frame->n_vectors;
1080
1081 next_index = node->cached_next_index;
1082
1083 int encap_pkts = 0, bsid_pkts = 0;
1084
1085 while (n_left_from > 0)
1086 {
1087 u32 n_left_to_next;
1088
1089 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1090
1091 /* Quad - Loop */
1092 while (n_left_from >= 8 && n_left_to_next >= 4)
1093 {
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;
1101
1102 /* Prefetch next iteration. */
1103 {
1104 vlib_buffer_t *p4, *p5, *p6, *p7;
1105
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]);
1110
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);
1116
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);
1121 }
1122
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];
1127 from += 4;
1128 to_next += 4;
1129 n_left_from -= 4;
1130 n_left_to_next -= 4;
1131
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);
1136
1137 sl0 =
1138 pool_elt_at_index (sm->sid_lists,
1139 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1140 sl1 =
1141 pool_elt_at_index (sm->sid_lists,
1142 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1143 sl2 =
1144 pool_elt_at_index (sm->sid_lists,
1145 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1146 sl3 =
1147 pool_elt_at_index (sm->sid_lists,
1148 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1149
1150 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1151 (vec_len (sl0->rewrite) + b0->current_data));
1152 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1153 (vec_len (sl1->rewrite) + b1->current_data));
1154 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1155 (vec_len (sl2->rewrite) + b2->current_data));
1156 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1157 (vec_len (sl3->rewrite) + b3->current_data));
1158
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);
1163
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));
1172
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));
1177
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);
1182
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);
1187
1188 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1189 {
1190 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1191 {
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));
1198 }
1199
1200 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1201 {
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));
1208 }
1209
1210 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1211 {
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));
1218 }
1219
1220 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1221 {
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));
1228 }
1229 }
1230
1231 encap_pkts += 4;
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);
1235 }
1236
1237 /* Single loop for potentially the last three packets */
1238 while (n_left_from > 0 && n_left_to_next > 0)
1239 {
1240 u32 bi0;
1241 vlib_buffer_t *b0;
1242 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1243 ip6_sr_sl_t *sl0;
1244 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1245
1246 bi0 = from[0];
1247 to_next[0] = bi0;
1248 from += 1;
1249 to_next += 1;
1250 n_left_from -= 1;
1251 n_left_to_next -= 1;
1252 b0 = vlib_get_buffer (vm, bi0);
1253
1254 sl0 =
1255 pool_elt_at_index (sm->sid_lists,
1256 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1257
1258 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1259 (vec_len (sl0->rewrite) + b0->current_data));
1260
1261 ip0_encap = vlib_buffer_get_current (b0);
1262
1263 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1264 sl0->rewrite, vec_len (sl0->rewrite));
1265 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1266
1267 ip0 = vlib_buffer_get_current (b0);
1268
1269 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1270
1271 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1272 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1273 {
1274 sr_policy_rewrite_trace_t *tr =
1275 vlib_add_trace (vm, node, b0, sizeof (*tr));
1276 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1277 sizeof (tr->src.as_u8));
1278 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1279 sizeof (tr->dst.as_u8));
1280 }
1281
1282 encap_pkts++;
1283 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1284 n_left_to_next, bi0, next0);
1285 }
1286
1287 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1288 }
1289
1290 /* Update counters */
1291 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1292 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1293 encap_pkts);
1294 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1295 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1296 bsid_pkts);
1297
1298 return from_frame->n_vectors;
1299}
1300
1301/* *INDENT-OFF* */
1302VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1303 .function = sr_policy_rewrite_encaps,
1304 .name = "sr-pl-rewrite-encaps",
1305 .vector_size = sizeof (u32),
1306 .format_trace = format_sr_policy_rewrite_trace,
1307 .type = VLIB_NODE_TYPE_INTERNAL,
1308 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1309 .error_strings = sr_policy_rewrite_error_strings,
1310 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1311 .next_nodes = {
1312#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1313 foreach_sr_policy_rewrite_next
1314#undef _
1315 },
1316};
1317/* *INDENT-ON* */
1318
1319/**
1320 * @brief IPv4 encapsulation processing as per RFC2473
1321 */
1322static_always_inline void
1323encaps_processing_v4 (vlib_node_runtime_t * node,
1324 vlib_buffer_t * b0,
1325 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1326{
1327 u32 new_l0;
1328 ip6_sr_header_t *sr0;
1329
1330 u32 checksum0;
1331
1332 /* Inner IPv4: Decrement TTL & update checksum */
1333 ip0_encap->ttl -= 1;
1334 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1335 checksum0 += checksum0 >= 0xffff;
1336 ip0_encap->checksum = checksum0;
1337
1338 /* Outer IPv6: Update length, FL, proto */
1339 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1340 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1341 ip0->ip_version_traffic_class_and_flow_label =
1342 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1343 ((ip0_encap->tos & 0xFF) << 20));
1344 sr0 = (void *) (ip0 + 1);
1345 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1346}
1347
1348/**
1349 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1350 */
1351static uword
1352sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1353 vlib_frame_t * from_frame)
1354{
1355 ip6_sr_main_t *sm = &sr_main;
1356 u32 n_left_from, next_index, *from, *to_next;
1357
1358 from = vlib_frame_vector_args (from_frame);
1359 n_left_from = from_frame->n_vectors;
1360
1361 next_index = node->cached_next_index;
1362
1363 int encap_pkts = 0, bsid_pkts = 0;
1364
1365 while (n_left_from > 0)
1366 {
1367 u32 n_left_to_next;
1368
1369 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1370
1371 /* Quad - Loop */
1372 while (n_left_from >= 8 && n_left_to_next >= 4)
1373 {
1374 u32 bi0, bi1, bi2, bi3;
1375 vlib_buffer_t *b0, *b1, *b2, *b3;
1376 u32 next0, next1, next2, next3;
1377 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1378 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1379 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1380 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1381
1382 /* Prefetch next iteration. */
1383 {
1384 vlib_buffer_t *p4, *p5, *p6, *p7;
1385
1386 p4 = vlib_get_buffer (vm, from[4]);
1387 p5 = vlib_get_buffer (vm, from[5]);
1388 p6 = vlib_get_buffer (vm, from[6]);
1389 p7 = vlib_get_buffer (vm, from[7]);
1390
1391 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1392 vlib_prefetch_buffer_header (p4, LOAD);
1393 vlib_prefetch_buffer_header (p5, LOAD);
1394 vlib_prefetch_buffer_header (p6, LOAD);
1395 vlib_prefetch_buffer_header (p7, LOAD);
1396
1397 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1398 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1399 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1400 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1401 }
1402
1403 to_next[0] = bi0 = from[0];
1404 to_next[1] = bi1 = from[1];
1405 to_next[2] = bi2 = from[2];
1406 to_next[3] = bi3 = from[3];
1407 from += 4;
1408 to_next += 4;
1409 n_left_from -= 4;
1410 n_left_to_next -= 4;
1411
1412 b0 = vlib_get_buffer (vm, bi0);
1413 b1 = vlib_get_buffer (vm, bi1);
1414 b2 = vlib_get_buffer (vm, bi2);
1415 b3 = vlib_get_buffer (vm, bi3);
1416
1417 sl0 =
1418 pool_elt_at_index (sm->sid_lists,
1419 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1420 sl1 =
1421 pool_elt_at_index (sm->sid_lists,
1422 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1423 sl2 =
1424 pool_elt_at_index (sm->sid_lists,
1425 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1426 sl3 =
1427 pool_elt_at_index (sm->sid_lists,
1428 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1429
1430 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1431 (vec_len (sl0->rewrite) + b0->current_data));
1432 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1433 (vec_len (sl1->rewrite) + b1->current_data));
1434 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1435 (vec_len (sl2->rewrite) + b2->current_data));
1436 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1437 (vec_len (sl3->rewrite) + b3->current_data));
1438
1439 ip0_encap = vlib_buffer_get_current (b0);
1440 ip1_encap = vlib_buffer_get_current (b1);
1441 ip2_encap = vlib_buffer_get_current (b2);
1442 ip3_encap = vlib_buffer_get_current (b3);
1443
1444 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1445 sl0->rewrite, vec_len (sl0->rewrite));
1446 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1447 sl1->rewrite, vec_len (sl1->rewrite));
1448 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1449 sl2->rewrite, vec_len (sl2->rewrite));
1450 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1451 sl3->rewrite, vec_len (sl3->rewrite));
1452
1453 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1454 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1455 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1456 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1457
1458 ip0 = vlib_buffer_get_current (b0);
1459 ip1 = vlib_buffer_get_current (b1);
1460 ip2 = vlib_buffer_get_current (b2);
1461 ip3 = vlib_buffer_get_current (b3);
1462
1463 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1464 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1465 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1466 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1467
1468 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1469 {
1470 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1471 {
1472 sr_policy_rewrite_trace_t *tr =
1473 vlib_add_trace (vm, node, b0, sizeof (*tr));
1474 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1475 sizeof (tr->src.as_u8));
1476 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1477 sizeof (tr->dst.as_u8));
1478 }
1479
1480 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1481 {
1482 sr_policy_rewrite_trace_t *tr =
1483 vlib_add_trace (vm, node, b1, sizeof (*tr));
1484 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1485 sizeof (tr->src.as_u8));
1486 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1487 sizeof (tr->dst.as_u8));
1488 }
1489
1490 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1491 {
1492 sr_policy_rewrite_trace_t *tr =
1493 vlib_add_trace (vm, node, b2, sizeof (*tr));
1494 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1495 sizeof (tr->src.as_u8));
1496 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1497 sizeof (tr->dst.as_u8));
1498 }
1499
1500 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1501 {
1502 sr_policy_rewrite_trace_t *tr =
1503 vlib_add_trace (vm, node, b3, sizeof (*tr));
1504 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1505 sizeof (tr->src.as_u8));
1506 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1507 sizeof (tr->dst.as_u8));
1508 }
1509 }
1510
1511 encap_pkts += 4;
1512 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1513 n_left_to_next, bi0, bi1, bi2, bi3,
1514 next0, next1, next2, next3);
1515 }
1516
1517 /* Single loop for potentially the last three packets */
1518 while (n_left_from > 0 && n_left_to_next > 0)
1519 {
1520 u32 bi0;
1521 vlib_buffer_t *b0;
1522 ip6_header_t *ip0 = 0;
1523 ip4_header_t *ip0_encap = 0;
1524 ip6_sr_sl_t *sl0;
1525 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1526
1527 bi0 = from[0];
1528 to_next[0] = bi0;
1529 from += 1;
1530 to_next += 1;
1531 n_left_from -= 1;
1532 n_left_to_next -= 1;
1533 b0 = vlib_get_buffer (vm, bi0);
1534
1535 sl0 =
1536 pool_elt_at_index (sm->sid_lists,
1537 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1538
1539 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1540 (vec_len (sl0->rewrite) + b0->current_data));
1541
1542 ip0_encap = vlib_buffer_get_current (b0);
1543
1544 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1545 sl0->rewrite, vec_len (sl0->rewrite));
1546 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1547
1548 ip0 = vlib_buffer_get_current (b0);
1549
1550 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1551
1552 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1553 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1554 {
1555 sr_policy_rewrite_trace_t *tr =
1556 vlib_add_trace (vm, node, b0, sizeof (*tr));
1557 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1558 sizeof (tr->src.as_u8));
1559 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1560 sizeof (tr->dst.as_u8));
1561 }
1562
1563 encap_pkts++;
1564 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1565 n_left_to_next, bi0, next0);
1566 }
1567
1568 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1569 }
1570
1571 /* Update counters */
1572 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1573 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1574 encap_pkts);
1575 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1576 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1577 bsid_pkts);
1578
1579 return from_frame->n_vectors;
1580}
1581
1582/* *INDENT-OFF* */
1583VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1584 .function = sr_policy_rewrite_encaps_v4,
1585 .name = "sr-pl-rewrite-encaps-v4",
1586 .vector_size = sizeof (u32),
1587 .format_trace = format_sr_policy_rewrite_trace,
1588 .type = VLIB_NODE_TYPE_INTERNAL,
1589 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1590 .error_strings = sr_policy_rewrite_error_strings,
1591 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1592 .next_nodes = {
1593#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1594 foreach_sr_policy_rewrite_next
1595#undef _
1596 },
1597};
1598/* *INDENT-ON* */
1599
1600always_inline u32
1601ip_flow_hash (void *data)
1602{
1603 ip4_header_t *iph = (ip4_header_t *) data;
1604
1605 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1606 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1607 else
1608 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1609}
1610
1611always_inline u64
1612mac_to_u64 (u8 * m)
1613{
1614 return (*((u64 *) m) & 0xffffffffffff);
1615}
1616
1617always_inline u32
1618l2_flow_hash (vlib_buffer_t * b0)
1619{
1620 ethernet_header_t *eh;
1621 u64 a, b, c;
1622 uword is_ip, eh_size;
1623 u16 eh_type;
1624
1625 eh = vlib_buffer_get_current (b0);
1626 eh_type = clib_net_to_host_u16 (eh->type);
1627 eh_size = ethernet_buffer_header_size (b0);
1628
1629 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1630
1631 /* since we have 2 cache lines, use them */
1632 if (is_ip)
1633 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1634 else
1635 a = eh->type;
1636
1637 b = mac_to_u64 ((u8 *) eh->dst_address);
1638 c = mac_to_u64 ((u8 *) eh->src_address);
1639 hash_mix64 (a, b, c);
1640
1641 return (u32) c;
1642}
1643
1644/**
1645 * @brief Graph node for applying a SR policy into a L2 frame
1646 */
1647static uword
1648sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1649 vlib_frame_t * from_frame)
1650{
1651 ip6_sr_main_t *sm = &sr_main;
1652 u32 n_left_from, next_index, *from, *to_next;
1653
1654 from = vlib_frame_vector_args (from_frame);
1655 n_left_from = from_frame->n_vectors;
1656
1657 next_index = node->cached_next_index;
1658
1659 int encap_pkts = 0, bsid_pkts = 0;
1660
1661 while (n_left_from > 0)
1662 {
1663 u32 n_left_to_next;
1664
1665 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1666
1667 /* Quad - Loop */
1668 while (n_left_from >= 8 && n_left_to_next >= 4)
1669 {
1670 u32 bi0, bi1, bi2, bi3;
1671 vlib_buffer_t *b0, *b1, *b2, *b3;
1672 u32 next0, next1, next2, next3;
1673 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1674 ethernet_header_t *en0, *en1, *en2, *en3;
1675 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1676 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1677 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1678 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1679
1680 /* Prefetch next iteration. */
1681 {
1682 vlib_buffer_t *p4, *p5, *p6, *p7;
1683
1684 p4 = vlib_get_buffer (vm, from[4]);
1685 p5 = vlib_get_buffer (vm, from[5]);
1686 p6 = vlib_get_buffer (vm, from[6]);
1687 p7 = vlib_get_buffer (vm, from[7]);
1688
1689 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1690 vlib_prefetch_buffer_header (p4, LOAD);
1691 vlib_prefetch_buffer_header (p5, LOAD);
1692 vlib_prefetch_buffer_header (p6, LOAD);
1693 vlib_prefetch_buffer_header (p7, LOAD);
1694
1695 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1696 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1697 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1698 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1699 }
1700
1701 to_next[0] = bi0 = from[0];
1702 to_next[1] = bi1 = from[1];
1703 to_next[2] = bi2 = from[2];
1704 to_next[3] = bi3 = from[3];
1705 from += 4;
1706 to_next += 4;
1707 n_left_from -= 4;
1708 n_left_to_next -= 4;
1709
1710 b0 = vlib_get_buffer (vm, bi0);
1711 b1 = vlib_get_buffer (vm, bi1);
1712 b2 = vlib_get_buffer (vm, bi2);
1713 b3 = vlib_get_buffer (vm, bi3);
1714
1715 sp0 = pool_elt_at_index (sm->sr_policies,
1716 sm->sw_iface_sr_policies[vnet_buffer
1717 (b0)->sw_if_index
1718 [VLIB_RX]]);
1719
1720 sp1 = pool_elt_at_index (sm->sr_policies,
1721 sm->sw_iface_sr_policies[vnet_buffer
1722 (b1)->sw_if_index
1723 [VLIB_RX]]);
1724
1725 sp2 = pool_elt_at_index (sm->sr_policies,
1726 sm->sw_iface_sr_policies[vnet_buffer
1727 (b2)->sw_if_index
1728 [VLIB_RX]]);
1729
1730 sp3 = pool_elt_at_index (sm->sr_policies,
1731 sm->sw_iface_sr_policies[vnet_buffer
1732 (b3)->sw_if_index
1733 [VLIB_RX]]);
1734
1735 if (vec_len (sp0->segments_lists) == 1)
1736 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1737 else
1738 {
1739 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1740 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1741 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1742 (vec_len (sp0->segments_lists) - 1))];
1743 }
1744
1745 if (vec_len (sp1->segments_lists) == 1)
1746 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1747 else
1748 {
1749 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1750 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1751 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1752 (vec_len (sp1->segments_lists) - 1))];
1753 }
1754
1755 if (vec_len (sp2->segments_lists) == 1)
1756 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1757 else
1758 {
1759 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1760 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1761 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1762 (vec_len (sp2->segments_lists) - 1))];
1763 }
1764
1765 if (vec_len (sp3->segments_lists) == 1)
1766 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1767 else
1768 {
1769 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1770 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1771 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1772 (vec_len (sp3->segments_lists) - 1))];
1773 }
1774
1775 sl0 =
1776 pool_elt_at_index (sm->sid_lists,
1777 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1778 sl1 =
1779 pool_elt_at_index (sm->sid_lists,
1780 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1781 sl2 =
1782 pool_elt_at_index (sm->sid_lists,
1783 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1784 sl3 =
1785 pool_elt_at_index (sm->sid_lists,
1786 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1787
1788 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1789 (vec_len (sl0->rewrite) + b0->current_data));
1790 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1791 (vec_len (sl1->rewrite) + b1->current_data));
1792 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1793 (vec_len (sl2->rewrite) + b2->current_data));
1794 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1795 (vec_len (sl3->rewrite) + b3->current_data));
1796
1797 en0 = vlib_buffer_get_current (b0);
1798 en1 = vlib_buffer_get_current (b1);
1799 en2 = vlib_buffer_get_current (b2);
1800 en3 = vlib_buffer_get_current (b3);
1801
1802 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1803 vec_len (sl0->rewrite));
1804 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1805 vec_len (sl1->rewrite));
1806 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1807 vec_len (sl2->rewrite));
1808 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1809 vec_len (sl3->rewrite));
1810
1811 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1812 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1813 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1814 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1815
1816 ip0 = vlib_buffer_get_current (b0);
1817 ip1 = vlib_buffer_get_current (b1);
1818 ip2 = vlib_buffer_get_current (b2);
1819 ip3 = vlib_buffer_get_current (b3);
1820
1821 ip0->payload_length =
1822 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1823 ip1->payload_length =
1824 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1825 ip2->payload_length =
1826 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1827 ip3->payload_length =
1828 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1829
1830 sr0 = (void *) (ip0 + 1);
1831 sr1 = (void *) (ip1 + 1);
1832 sr2 = (void *) (ip2 + 1);
1833 sr3 = (void *) (ip3 + 1);
1834
1835 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1836 IP_PROTOCOL_IP6_NONXT;
1837
1838 /* Which Traffic class and flow label do I set ? */
1839 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1840
1841 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1842 {
1843 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1844 {
1845 sr_policy_rewrite_trace_t *tr =
1846 vlib_add_trace (vm, node, b0, sizeof (*tr));
1847 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1848 sizeof (tr->src.as_u8));
1849 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1850 sizeof (tr->dst.as_u8));
1851 }
1852
1853 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1854 {
1855 sr_policy_rewrite_trace_t *tr =
1856 vlib_add_trace (vm, node, b1, sizeof (*tr));
1857 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1858 sizeof (tr->src.as_u8));
1859 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1860 sizeof (tr->dst.as_u8));
1861 }
1862
1863 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1864 {
1865 sr_policy_rewrite_trace_t *tr =
1866 vlib_add_trace (vm, node, b2, sizeof (*tr));
1867 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1868 sizeof (tr->src.as_u8));
1869 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1870 sizeof (tr->dst.as_u8));
1871 }
1872
1873 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1874 {
1875 sr_policy_rewrite_trace_t *tr =
1876 vlib_add_trace (vm, node, b3, sizeof (*tr));
1877 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1878 sizeof (tr->src.as_u8));
1879 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1880 sizeof (tr->dst.as_u8));
1881 }
1882 }
1883
1884 encap_pkts += 4;
1885 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1886 n_left_to_next, bi0, bi1, bi2, bi3,
1887 next0, next1, next2, next3);
1888 }
1889
1890 /* Single loop for potentially the last three packets */
1891 while (n_left_from > 0 && n_left_to_next > 0)
1892 {
1893 u32 bi0;
1894 vlib_buffer_t *b0;
1895 ip6_header_t *ip0 = 0;
1896 ip6_sr_header_t *sr0;
1897 ethernet_header_t *en0;
1898 ip6_sr_policy_t *sp0;
1899 ip6_sr_sl_t *sl0;
1900 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1901
1902 bi0 = from[0];
1903 to_next[0] = bi0;
1904 from += 1;
1905 to_next += 1;
1906 n_left_from -= 1;
1907 n_left_to_next -= 1;
1908 b0 = vlib_get_buffer (vm, bi0);
1909
1910 /* Find the SR policy */
1911 sp0 = pool_elt_at_index (sm->sr_policies,
1912 sm->sw_iface_sr_policies[vnet_buffer
1913 (b0)->sw_if_index
1914 [VLIB_RX]]);
1915
1916 /* In case there is more than one SL, LB among them */
1917 if (vec_len (sp0->segments_lists) == 1)
1918 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1919 else
1920 {
1921 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1922 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1923 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1924 (vec_len (sp0->segments_lists) - 1))];
1925 }
1926 sl0 =
1927 pool_elt_at_index (sm->sid_lists,
1928 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1929
1930 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
1931 (vec_len (sl0->rewrite) + b0->current_data));
1932
1933 en0 = vlib_buffer_get_current (b0);
1934
1935 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1936 vec_len (sl0->rewrite));
1937
1938 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1939
1940 ip0 = vlib_buffer_get_current (b0);
1941
1942 ip0->payload_length =
1943 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1944
1945 sr0 = (void *) (ip0 + 1);
1946 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1947
1948 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1949 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1950 {
1951 sr_policy_rewrite_trace_t *tr =
1952 vlib_add_trace (vm, node, b0, sizeof (*tr));
1953 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1954 sizeof (tr->src.as_u8));
1955 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1956 sizeof (tr->dst.as_u8));
1957 }
1958
1959 encap_pkts++;
1960 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1961 n_left_to_next, bi0, next0);
1962 }
1963
1964 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1965 }
1966
1967 /* Update counters */
1968 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1969 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1970 encap_pkts);
1971 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1972 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1973 bsid_pkts);
1974
1975 return from_frame->n_vectors;
1976}
1977
1978/* *INDENT-OFF* */
1979VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1980 .function = sr_policy_rewrite_encaps_l2,
1981 .name = "sr-pl-rewrite-encaps-l2",
1982 .vector_size = sizeof (u32),
1983 .format_trace = format_sr_policy_rewrite_trace,
1984 .type = VLIB_NODE_TYPE_INTERNAL,
1985 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1986 .error_strings = sr_policy_rewrite_error_strings,
1987 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1988 .next_nodes = {
1989#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1990 foreach_sr_policy_rewrite_next
1991#undef _
1992 },
1993};
1994/* *INDENT-ON* */
1995
1996/**
1997 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1998 */
1999static uword
2000sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2001 vlib_frame_t * from_frame)
2002{
2003 ip6_sr_main_t *sm = &sr_main;
2004 u32 n_left_from, next_index, *from, *to_next;
2005
2006 from = vlib_frame_vector_args (from_frame);
2007 n_left_from = from_frame->n_vectors;
2008
2009 next_index = node->cached_next_index;
2010
2011 int insert_pkts = 0, bsid_pkts = 0;
2012
2013 while (n_left_from > 0)
2014 {
2015 u32 n_left_to_next;
2016
2017 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2018
2019 /* Quad - Loop */
2020 while (n_left_from >= 8 && n_left_to_next >= 4)
2021 {
2022 u32 bi0, bi1, bi2, bi3;
2023 vlib_buffer_t *b0, *b1, *b2, *b3;
2024 u32 next0, next1, next2, next3;
2025 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2026 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2027 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2028 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2029 u16 new_l0, new_l1, new_l2, new_l3;
2030
2031 /* Prefetch next iteration. */
2032 {
2033 vlib_buffer_t *p4, *p5, *p6, *p7;
2034
2035 p4 = vlib_get_buffer (vm, from[4]);
2036 p5 = vlib_get_buffer (vm, from[5]);
2037 p6 = vlib_get_buffer (vm, from[6]);
2038 p7 = vlib_get_buffer (vm, from[7]);
2039
2040 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2041 vlib_prefetch_buffer_header (p4, LOAD);
2042 vlib_prefetch_buffer_header (p5, LOAD);
2043 vlib_prefetch_buffer_header (p6, LOAD);
2044 vlib_prefetch_buffer_header (p7, LOAD);
2045
2046 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2047 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2048 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2049 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2050 }
2051
2052 to_next[0] = bi0 = from[0];
2053 to_next[1] = bi1 = from[1];
2054 to_next[2] = bi2 = from[2];
2055 to_next[3] = bi3 = from[3];
2056 from += 4;
2057 to_next += 4;
2058 n_left_from -= 4;
2059 n_left_to_next -= 4;
2060
2061 b0 = vlib_get_buffer (vm, bi0);
2062 b1 = vlib_get_buffer (vm, bi1);
2063 b2 = vlib_get_buffer (vm, bi2);
2064 b3 = vlib_get_buffer (vm, bi3);
2065
2066 sl0 =
2067 pool_elt_at_index (sm->sid_lists,
2068 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2069 sl1 =
2070 pool_elt_at_index (sm->sid_lists,
2071 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2072 sl2 =
2073 pool_elt_at_index (sm->sid_lists,
2074 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2075 sl3 =
2076 pool_elt_at_index (sm->sid_lists,
2077 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2078
2079 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2080 (vec_len (sl0->rewrite) + b0->current_data));
2081 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2082 (vec_len (sl1->rewrite) + b1->current_data));
2083 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2084 (vec_len (sl2->rewrite) + b2->current_data));
2085 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2086 (vec_len (sl3->rewrite) + b3->current_data));
2087
2088 ip0 = vlib_buffer_get_current (b0);
2089 ip1 = vlib_buffer_get_current (b1);
2090 ip2 = vlib_buffer_get_current (b2);
2091 ip3 = vlib_buffer_get_current (b3);
2092
2093 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2094 sr0 =
2095 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2096 ip6_ext_header_len (ip0 + 1));
2097 else
2098 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2099
2100 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2101 sr1 =
2102 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2103 ip6_ext_header_len (ip1 + 1));
2104 else
2105 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2106
2107 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2108 sr2 =
2109 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2110 ip6_ext_header_len (ip2 + 1));
2111 else
2112 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2113
2114 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2115 sr3 =
2116 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2117 ip6_ext_header_len (ip3 + 1));
2118 else
2119 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2120
2121 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2122 (void *) sr0 - (void *) ip0);
2123 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2124 (void *) sr1 - (void *) ip1);
2125 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2126 (void *) sr2 - (void *) ip2);
2127 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2128 (void *) sr3 - (void *) ip3);
2129
2130 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2131 vec_len (sl0->rewrite));
2132 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2133 vec_len (sl1->rewrite));
2134 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2135 vec_len (sl2->rewrite));
2136 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2137 vec_len (sl3->rewrite));
2138
2139 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2140 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2141 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2142 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2143
2144 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2145 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2146 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2147 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2148
2149 ip0->hop_limit -= 1;
2150 ip1->hop_limit -= 1;
2151 ip2->hop_limit -= 1;
2152 ip3->hop_limit -= 1;
2153
2154 new_l0 =
2155 clib_net_to_host_u16 (ip0->payload_length) +
2156 vec_len (sl0->rewrite);
2157 new_l1 =
2158 clib_net_to_host_u16 (ip1->payload_length) +
2159 vec_len (sl1->rewrite);
2160 new_l2 =
2161 clib_net_to_host_u16 (ip2->payload_length) +
2162 vec_len (sl2->rewrite);
2163 new_l3 =
2164 clib_net_to_host_u16 (ip3->payload_length) +
2165 vec_len (sl3->rewrite);
2166
2167 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2168 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2169 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2170 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2171
2172 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2173 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2174 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2175 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2176
2177 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2178 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2179 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2180 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2181 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2182 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2183 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2184 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2185
2186 ip0->dst_address.as_u64[0] =
2187 (sr0->segments + sr0->segments_left)->as_u64[0];
2188 ip0->dst_address.as_u64[1] =
2189 (sr0->segments + sr0->segments_left)->as_u64[1];
2190 ip1->dst_address.as_u64[0] =
2191 (sr1->segments + sr1->segments_left)->as_u64[0];
2192 ip1->dst_address.as_u64[1] =
2193 (sr1->segments + sr1->segments_left)->as_u64[1];
2194 ip2->dst_address.as_u64[0] =
2195 (sr2->segments + sr2->segments_left)->as_u64[0];
2196 ip2->dst_address.as_u64[1] =
2197 (sr2->segments + sr2->segments_left)->as_u64[1];
2198 ip3->dst_address.as_u64[0] =
2199 (sr3->segments + sr3->segments_left)->as_u64[0];
2200 ip3->dst_address.as_u64[1] =
2201 (sr3->segments + sr3->segments_left)->as_u64[1];
2202
2203 ip6_ext_header_t *ip_ext;
2204 if (ip0 + 1 == (void *) sr0)
2205 {
2206 sr0->protocol = ip0->protocol;
2207 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2208 }
2209 else
2210 {
2211 ip_ext = (void *) (ip0 + 1);
2212 sr0->protocol = ip_ext->next_hdr;
2213 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2214 }
2215
2216 if (ip1 + 1 == (void *) sr1)
2217 {
2218 sr1->protocol = ip1->protocol;
2219 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2220 }
2221 else
2222 {
2223 ip_ext = (void *) (ip2 + 1);
2224 sr2->protocol = ip_ext->next_hdr;
2225 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2226 }
2227
2228 if (ip2 + 1 == (void *) sr2)
2229 {
2230 sr2->protocol = ip2->protocol;
2231 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2232 }
2233 else
2234 {
2235 ip_ext = (void *) (ip2 + 1);
2236 sr2->protocol = ip_ext->next_hdr;
2237 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2238 }
2239
2240 if (ip3 + 1 == (void *) sr3)
2241 {
2242 sr3->protocol = ip3->protocol;
2243 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2244 }
2245 else
2246 {
2247 ip_ext = (void *) (ip3 + 1);
2248 sr3->protocol = ip_ext->next_hdr;
2249 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2250 }
2251
2252 insert_pkts += 4;
2253
2254 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2255 {
2256 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2257 {
2258 sr_policy_rewrite_trace_t *tr =
2259 vlib_add_trace (vm, node, b0, sizeof (*tr));
2260 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2261 sizeof (tr->src.as_u8));
2262 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2263 sizeof (tr->dst.as_u8));
2264 }
2265
2266 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2267 {
2268 sr_policy_rewrite_trace_t *tr =
2269 vlib_add_trace (vm, node, b1, sizeof (*tr));
2270 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2271 sizeof (tr->src.as_u8));
2272 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2273 sizeof (tr->dst.as_u8));
2274 }
2275
2276 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2277 {
2278 sr_policy_rewrite_trace_t *tr =
2279 vlib_add_trace (vm, node, b2, sizeof (*tr));
2280 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2281 sizeof (tr->src.as_u8));
2282 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2283 sizeof (tr->dst.as_u8));
2284 }
2285
2286 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2287 {
2288 sr_policy_rewrite_trace_t *tr =
2289 vlib_add_trace (vm, node, b3, sizeof (*tr));
2290 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2291 sizeof (tr->src.as_u8));
2292 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2293 sizeof (tr->dst.as_u8));
2294 }
2295 }
2296
2297 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2298 n_left_to_next, bi0, bi1, bi2, bi3,
2299 next0, next1, next2, next3);
2300 }
2301
2302 /* Single loop for potentially the last three packets */
2303 while (n_left_from > 0 && n_left_to_next > 0)
2304 {
2305 u32 bi0;
2306 vlib_buffer_t *b0;
2307 ip6_header_t *ip0 = 0;
2308 ip6_sr_header_t *sr0 = 0;
2309 ip6_sr_sl_t *sl0;
2310 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2311 u16 new_l0 = 0;
2312
2313 bi0 = from[0];
2314 to_next[0] = bi0;
2315 from += 1;
2316 to_next += 1;
2317 n_left_from -= 1;
2318 n_left_to_next -= 1;
2319
2320 b0 = vlib_get_buffer (vm, bi0);
2321 sl0 =
2322 pool_elt_at_index (sm->sid_lists,
2323 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2324 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2325 (vec_len (sl0->rewrite) + b0->current_data));
2326
2327 ip0 = vlib_buffer_get_current (b0);
2328
2329 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2330 sr0 =
2331 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2332 ip6_ext_header_len (ip0 + 1));
2333 else
2334 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2335
2336 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2337 (void *) sr0 - (void *) ip0);
2338 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2339 vec_len (sl0->rewrite));
2340
2341 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2342
2343 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2344 ip0->hop_limit -= 1;
2345 new_l0 =
2346 clib_net_to_host_u16 (ip0->payload_length) +
2347 vec_len (sl0->rewrite);
2348 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2349
2350 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2351 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2352 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2353
2354 ip0->dst_address.as_u64[0] =
2355 (sr0->segments + sr0->segments_left)->as_u64[0];
2356 ip0->dst_address.as_u64[1] =
2357 (sr0->segments + sr0->segments_left)->as_u64[1];
2358
2359 if (ip0 + 1 == (void *) sr0)
2360 {
2361 sr0->protocol = ip0->protocol;
2362 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2363 }
2364 else
2365 {
2366 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2367 sr0->protocol = ip_ext->next_hdr;
2368 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2369 }
2370
2371 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2372 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2373 {
2374 sr_policy_rewrite_trace_t *tr =
2375 vlib_add_trace (vm, node, b0, sizeof (*tr));
2376 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2377 sizeof (tr->src.as_u8));
2378 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2379 sizeof (tr->dst.as_u8));
2380 }
2381
2382 insert_pkts++;
2383
2384 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2385 n_left_to_next, bi0, next0);
2386 }
2387
2388 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2389 }
2390
2391 /* Update counters */
2392 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2393 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2394 insert_pkts);
2395 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2396 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2397 bsid_pkts);
2398 return from_frame->n_vectors;
2399}
2400
2401/* *INDENT-OFF* */
2402VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2403 .function = sr_policy_rewrite_insert,
2404 .name = "sr-pl-rewrite-insert",
2405 .vector_size = sizeof (u32),
2406 .format_trace = format_sr_policy_rewrite_trace,
2407 .type = VLIB_NODE_TYPE_INTERNAL,
2408 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2409 .error_strings = sr_policy_rewrite_error_strings,
2410 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2411 .next_nodes = {
2412#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2413 foreach_sr_policy_rewrite_next
2414#undef _
2415 },
2416};
2417/* *INDENT-ON* */
2418
2419/**
2420 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2421 */
2422static uword
2423sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2424 vlib_frame_t * from_frame)
2425{
2426 ip6_sr_main_t *sm = &sr_main;
2427 u32 n_left_from, next_index, *from, *to_next;
2428
2429 from = vlib_frame_vector_args (from_frame);
2430 n_left_from = from_frame->n_vectors;
2431
2432 next_index = node->cached_next_index;
2433
2434 int insert_pkts = 0, bsid_pkts = 0;
2435
2436 while (n_left_from > 0)
2437 {
2438 u32 n_left_to_next;
2439
2440 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2441
2442 /* Quad - Loop */
2443 while (n_left_from >= 8 && n_left_to_next >= 4)
2444 {
2445 u32 bi0, bi1, bi2, bi3;
2446 vlib_buffer_t *b0, *b1, *b2, *b3;
2447 u32 next0, next1, next2, next3;
2448 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2449 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2450 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2451 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2452 u16 new_l0, new_l1, new_l2, new_l3;
2453
2454 /* Prefetch next iteration. */
2455 {
2456 vlib_buffer_t *p4, *p5, *p6, *p7;
2457
2458 p4 = vlib_get_buffer (vm, from[4]);
2459 p5 = vlib_get_buffer (vm, from[5]);
2460 p6 = vlib_get_buffer (vm, from[6]);
2461 p7 = vlib_get_buffer (vm, from[7]);
2462
2463 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2464 vlib_prefetch_buffer_header (p4, LOAD);
2465 vlib_prefetch_buffer_header (p5, LOAD);
2466 vlib_prefetch_buffer_header (p6, LOAD);
2467 vlib_prefetch_buffer_header (p7, LOAD);
2468
2469 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2470 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2471 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2472 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2473 }
2474
2475 to_next[0] = bi0 = from[0];
2476 to_next[1] = bi1 = from[1];
2477 to_next[2] = bi2 = from[2];
2478 to_next[3] = bi3 = from[3];
2479 from += 4;
2480 to_next += 4;
2481 n_left_from -= 4;
2482 n_left_to_next -= 4;
2483
2484 b0 = vlib_get_buffer (vm, bi0);
2485 b1 = vlib_get_buffer (vm, bi1);
2486 b2 = vlib_get_buffer (vm, bi2);
2487 b3 = vlib_get_buffer (vm, bi3);
2488
2489 sl0 =
2490 pool_elt_at_index (sm->sid_lists,
2491 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2492 sl1 =
2493 pool_elt_at_index (sm->sid_lists,
2494 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2495 sl2 =
2496 pool_elt_at_index (sm->sid_lists,
2497 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2498 sl3 =
2499 pool_elt_at_index (sm->sid_lists,
2500 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2501
2502 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2503 (vec_len (sl0->rewrite_bsid) + b0->current_data));
2504 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2505 (vec_len (sl1->rewrite_bsid) + b1->current_data));
2506 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2507 (vec_len (sl2->rewrite_bsid) + b2->current_data));
2508 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2509 (vec_len (sl3->rewrite_bsid) + b3->current_data));
2510
2511 ip0 = vlib_buffer_get_current (b0);
2512 ip1 = vlib_buffer_get_current (b1);
2513 ip2 = vlib_buffer_get_current (b2);
2514 ip3 = vlib_buffer_get_current (b3);
2515
2516 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2517 sr0 =
2518 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2519 ip6_ext_header_len (ip0 + 1));
2520 else
2521 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2522
2523 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2524 sr1 =
2525 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2526 ip6_ext_header_len (ip1 + 1));
2527 else
2528 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2529
2530 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2531 sr2 =
2532 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2533 ip6_ext_header_len (ip2 + 1));
2534 else
2535 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2536
2537 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2538 sr3 =
2539 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2540 ip6_ext_header_len (ip3 + 1));
2541 else
2542 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2543
2544 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2545 (void *) sr0 - (void *) ip0);
2546 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2547 (void *) sr1 - (void *) ip1);
2548 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2549 (void *) sr2 - (void *) ip2);
2550 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2551 (void *) sr3 - (void *) ip3);
2552
2553 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2554 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2555 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2556 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2557 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2558 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2559 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2560 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2561
2562 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2563 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2564 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2565 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2566
2567 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2568 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2569 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2570 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2571
2572 ip0->hop_limit -= 1;
2573 ip1->hop_limit -= 1;
2574 ip2->hop_limit -= 1;
2575 ip3->hop_limit -= 1;
2576
2577 new_l0 =
2578 clib_net_to_host_u16 (ip0->payload_length) +
2579 vec_len (sl0->rewrite_bsid);
2580 new_l1 =
2581 clib_net_to_host_u16 (ip1->payload_length) +
2582 vec_len (sl1->rewrite_bsid);
2583 new_l2 =
2584 clib_net_to_host_u16 (ip2->payload_length) +
2585 vec_len (sl2->rewrite_bsid);
2586 new_l3 =
2587 clib_net_to_host_u16 (ip3->payload_length) +
2588 vec_len (sl3->rewrite_bsid);
2589
2590 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2591 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2592 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2593 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2594
2595 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2596 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2597 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2598 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2599
2600 ip0->dst_address.as_u64[0] =
2601 (sr0->segments + sr0->segments_left)->as_u64[0];
2602 ip0->dst_address.as_u64[1] =
2603 (sr0->segments + sr0->segments_left)->as_u64[1];
2604 ip1->dst_address.as_u64[0] =
2605 (sr1->segments + sr1->segments_left)->as_u64[0];
2606 ip1->dst_address.as_u64[1] =
2607 (sr1->segments + sr1->segments_left)->as_u64[1];
2608 ip2->dst_address.as_u64[0] =
2609 (sr2->segments + sr2->segments_left)->as_u64[0];
2610 ip2->dst_address.as_u64[1] =
2611 (sr2->segments + sr2->segments_left)->as_u64[1];
2612 ip3->dst_address.as_u64[0] =
2613 (sr3->segments + sr3->segments_left)->as_u64[0];
2614 ip3->dst_address.as_u64[1] =
2615 (sr3->segments + sr3->segments_left)->as_u64[1];
2616
2617 ip6_ext_header_t *ip_ext;
2618 if (ip0 + 1 == (void *) sr0)
2619 {
2620 sr0->protocol = ip0->protocol;
2621 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2622 }
2623 else
2624 {
2625 ip_ext = (void *) (ip0 + 1);
2626 sr0->protocol = ip_ext->next_hdr;
2627 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2628 }
2629
2630 if (ip1 + 1 == (void *) sr1)
2631 {
2632 sr1->protocol = ip1->protocol;
2633 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2634 }
2635 else
2636 {
2637 ip_ext = (void *) (ip2 + 1);
2638 sr2->protocol = ip_ext->next_hdr;
2639 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2640 }
2641
2642 if (ip2 + 1 == (void *) sr2)
2643 {
2644 sr2->protocol = ip2->protocol;
2645 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2646 }
2647 else
2648 {
2649 ip_ext = (void *) (ip2 + 1);
2650 sr2->protocol = ip_ext->next_hdr;
2651 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2652 }
2653
2654 if (ip3 + 1 == (void *) sr3)
2655 {
2656 sr3->protocol = ip3->protocol;
2657 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2658 }
2659 else
2660 {
2661 ip_ext = (void *) (ip3 + 1);
2662 sr3->protocol = ip_ext->next_hdr;
2663 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2664 }
2665
2666 insert_pkts += 4;
2667
2668 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2669 {
2670 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2671 {
2672 sr_policy_rewrite_trace_t *tr =
2673 vlib_add_trace (vm, node, b0, sizeof (*tr));
2674 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2675 sizeof (tr->src.as_u8));
2676 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2677 sizeof (tr->dst.as_u8));
2678 }
2679
2680 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2681 {
2682 sr_policy_rewrite_trace_t *tr =
2683 vlib_add_trace (vm, node, b1, sizeof (*tr));
2684 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2685 sizeof (tr->src.as_u8));
2686 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2687 sizeof (tr->dst.as_u8));
2688 }
2689
2690 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2691 {
2692 sr_policy_rewrite_trace_t *tr =
2693 vlib_add_trace (vm, node, b2, sizeof (*tr));
2694 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2695 sizeof (tr->src.as_u8));
2696 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2697 sizeof (tr->dst.as_u8));
2698 }
2699
2700 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2701 {
2702 sr_policy_rewrite_trace_t *tr =
2703 vlib_add_trace (vm, node, b3, sizeof (*tr));
2704 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2705 sizeof (tr->src.as_u8));
2706 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2707 sizeof (tr->dst.as_u8));
2708 }
2709 }
2710
2711 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2712 n_left_to_next, bi0, bi1, bi2, bi3,
2713 next0, next1, next2, next3);
2714 }
2715
2716 /* Single loop for potentially the last three packets */
2717 while (n_left_from > 0 && n_left_to_next > 0)
2718 {
2719 u32 bi0;
2720 vlib_buffer_t *b0;
2721 ip6_header_t *ip0 = 0;
2722 ip6_sr_header_t *sr0 = 0;
2723 ip6_sr_sl_t *sl0;
2724 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2725 u16 new_l0 = 0;
2726
2727 bi0 = from[0];
2728 to_next[0] = bi0;
2729 from += 1;
2730 to_next += 1;
2731 n_left_from -= 1;
2732 n_left_to_next -= 1;
2733
2734 b0 = vlib_get_buffer (vm, bi0);
2735 sl0 =
2736 pool_elt_at_index (sm->sid_lists,
2737 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2738 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2739 (vec_len (sl0->rewrite_bsid) + b0->current_data));
2740
2741 ip0 = vlib_buffer_get_current (b0);
2742
2743 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2744 sr0 =
2745 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2746 ip6_ext_header_len (ip0 + 1));
2747 else
2748 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2749
2750 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2751 (void *) sr0 - (void *) ip0);
2752 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2753 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2754
2755 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2756
2757 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2758 ip0->hop_limit -= 1;
2759 new_l0 =
2760 clib_net_to_host_u16 (ip0->payload_length) +
2761 vec_len (sl0->rewrite_bsid);
2762 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2763
2764 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2765
2766 ip0->dst_address.as_u64[0] =
2767 (sr0->segments + sr0->segments_left)->as_u64[0];
2768 ip0->dst_address.as_u64[1] =
2769 (sr0->segments + sr0->segments_left)->as_u64[1];
2770
2771 if (ip0 + 1 == (void *) sr0)
2772 {
2773 sr0->protocol = ip0->protocol;
2774 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2775 }
2776 else
2777 {
2778 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2779 sr0->protocol = ip_ext->next_hdr;
2780 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2781 }
2782
2783 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2784 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2785 {
2786 sr_policy_rewrite_trace_t *tr =
2787 vlib_add_trace (vm, node, b0, sizeof (*tr));
2788 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2789 sizeof (tr->src.as_u8));
2790 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2791 sizeof (tr->dst.as_u8));
2792 }
2793
2794 insert_pkts++;
2795
2796 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2797 n_left_to_next, bi0, next0);
2798 }
2799
2800 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2801 }
2802
2803 /* Update counters */
2804 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2805 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2806 insert_pkts);
2807 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2808 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2809 bsid_pkts);
2810 return from_frame->n_vectors;
2811}
2812
2813/* *INDENT-OFF* */
2814VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2815 .function = sr_policy_rewrite_b_insert,
2816 .name = "sr-pl-rewrite-b-insert",
2817 .vector_size = sizeof (u32),
2818 .format_trace = format_sr_policy_rewrite_trace,
2819 .type = VLIB_NODE_TYPE_INTERNAL,
2820 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2821 .error_strings = sr_policy_rewrite_error_strings,
2822 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2823 .next_nodes = {
2824#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2825 foreach_sr_policy_rewrite_next
2826#undef _
2827 },
2828};
2829/* *INDENT-ON* */
2830
2831/**
2832 * @brief Function BSID encapsulation
2833 */
2834static_always_inline void
2835end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2836 vlib_buffer_t * b0,
2837 ip6_header_t * ip0,
2838 ip6_sr_header_t * sr0, u32 * next0)
2839{
2840 ip6_address_t *new_dst0;
2841
2842 if (PREDICT_FALSE (!sr0))
2843 goto error_bsid_encaps;
2844
2845 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2846 {
2847 if (PREDICT_TRUE (sr0->segments_left != 0))
2848 {
2849 sr0->segments_left -= 1;
2850 new_dst0 = (ip6_address_t *) (sr0->segments);
2851 new_dst0 += sr0->segments_left;
2852 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2853 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2854 return;
2855 }
2856 }
2857
2858error_bsid_encaps:
2859 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2860 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2861}
2862
2863/**
2864 * @brief Graph node for applying a SR policy BSID - Encapsulation
2865 */
2866static uword
2867sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2868 vlib_frame_t * from_frame)
2869{
2870 ip6_sr_main_t *sm = &sr_main;
2871 u32 n_left_from, next_index, *from, *to_next;
2872
2873 from = vlib_frame_vector_args (from_frame);
2874 n_left_from = from_frame->n_vectors;
2875
2876 next_index = node->cached_next_index;
2877
2878 int encap_pkts = 0, bsid_pkts = 0;
2879
2880 while (n_left_from > 0)
2881 {
2882 u32 n_left_to_next;
2883
2884 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2885
2886 /* Quad - Loop */
2887 while (n_left_from >= 8 && n_left_to_next >= 4)
2888 {
2889 u32 bi0, bi1, bi2, bi3;
2890 vlib_buffer_t *b0, *b1, *b2, *b3;
2891 u32 next0, next1, next2, next3;
2892 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2893 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2894 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2895 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2896 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2897 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2898
2899 /* Prefetch next iteration. */
2900 {
2901 vlib_buffer_t *p4, *p5, *p6, *p7;
2902
2903 p4 = vlib_get_buffer (vm, from[4]);
2904 p5 = vlib_get_buffer (vm, from[5]);
2905 p6 = vlib_get_buffer (vm, from[6]);
2906 p7 = vlib_get_buffer (vm, from[7]);
2907
2908 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2909 vlib_prefetch_buffer_header (p4, LOAD);
2910 vlib_prefetch_buffer_header (p5, LOAD);
2911 vlib_prefetch_buffer_header (p6, LOAD);
2912 vlib_prefetch_buffer_header (p7, LOAD);
2913
2914 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2915 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2916 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2917 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2918 }
2919
2920 to_next[0] = bi0 = from[0];
2921 to_next[1] = bi1 = from[1];
2922 to_next[2] = bi2 = from[2];
2923 to_next[3] = bi3 = from[3];
2924 from += 4;
2925 to_next += 4;
2926 n_left_from -= 4;
2927 n_left_to_next -= 4;
2928
2929 b0 = vlib_get_buffer (vm, bi0);
2930 b1 = vlib_get_buffer (vm, bi1);
2931 b2 = vlib_get_buffer (vm, bi2);
2932 b3 = vlib_get_buffer (vm, bi3);
2933
2934 sl0 =
2935 pool_elt_at_index (sm->sid_lists,
2936 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2937 sl1 =
2938 pool_elt_at_index (sm->sid_lists,
2939 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2940 sl2 =
2941 pool_elt_at_index (sm->sid_lists,
2942 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2943 sl3 =
2944 pool_elt_at_index (sm->sid_lists,
2945 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2946
2947 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2948 (vec_len (sl0->rewrite) + b0->current_data));
2949 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2950 (vec_len (sl1->rewrite) + b1->current_data));
2951 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2952 (vec_len (sl2->rewrite) + b2->current_data));
2953 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
2954 (vec_len (sl3->rewrite) + b3->current_data));
2955
2956 ip0_encap = vlib_buffer_get_current (b0);
2957 ip1_encap = vlib_buffer_get_current (b1);
2958 ip2_encap = vlib_buffer_get_current (b2);
2959 ip3_encap = vlib_buffer_get_current (b3);
2960
2961 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2962 IP_PROTOCOL_IPV6_ROUTE);
2963 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2964 IP_PROTOCOL_IPV6_ROUTE);
2965 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2966 IP_PROTOCOL_IPV6_ROUTE);
2967 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2968 IP_PROTOCOL_IPV6_ROUTE);
2969
2970 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2971 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2972 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2973 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2974
2975 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2976 sl0->rewrite, vec_len (sl0->rewrite));
2977 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2978 sl1->rewrite, vec_len (sl1->rewrite));
2979 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2980 sl2->rewrite, vec_len (sl2->rewrite));
2981 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2982 sl3->rewrite, vec_len (sl3->rewrite));
2983
2984 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2985 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2986 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2987 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2988
2989 ip0 = vlib_buffer_get_current (b0);
2990 ip1 = vlib_buffer_get_current (b1);
2991 ip2 = vlib_buffer_get_current (b2);
2992 ip3 = vlib_buffer_get_current (b3);
2993
2994 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2995 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2996 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2997 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2998
2999 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3000 {
3001 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3002 {
3003 sr_policy_rewrite_trace_t *tr =
3004 vlib_add_trace (vm, node, b0, sizeof (*tr));
3005 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3006 sizeof (tr->src.as_u8));
3007 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3008 sizeof (tr->dst.as_u8));
3009 }
3010
3011 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
3012 {
3013 sr_policy_rewrite_trace_t *tr =
3014 vlib_add_trace (vm, node, b1, sizeof (*tr));
3015 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3016 sizeof (tr->src.as_u8));
3017 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3018 sizeof (tr->dst.as_u8));
3019 }
3020
3021 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3022 {
3023 sr_policy_rewrite_trace_t *tr =
3024 vlib_add_trace (vm, node, b2, sizeof (*tr));
3025 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3026 sizeof (tr->src.as_u8));
3027 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3028 sizeof (tr->dst.as_u8));
3029 }
3030
3031 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3032 {
3033 sr_policy_rewrite_trace_t *tr =
3034 vlib_add_trace (vm, node, b3, sizeof (*tr));
3035 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3036 sizeof (tr->src.as_u8));
3037 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3038 sizeof (tr->dst.as_u8));
3039 }
3040 }
3041
3042 encap_pkts += 4;
3043 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3044 n_left_to_next, bi0, bi1, bi2, bi3,
3045 next0, next1, next2, next3);
3046 }
3047
3048 /* Single loop for potentially the last three packets */
3049 while (n_left_from > 0 && n_left_to_next > 0)
3050 {
3051 u32 bi0;
3052 vlib_buffer_t *b0;
3053 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3054 ip6_ext_header_t *prev0;
3055 ip6_sr_header_t *sr0;
3056 ip6_sr_sl_t *sl0;
3057 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3058
3059 bi0 = from[0];
3060 to_next[0] = bi0;
3061 from += 1;
3062 to_next += 1;
3063 n_left_from -= 1;
3064 n_left_to_next -= 1;
3065 b0 = vlib_get_buffer (vm, bi0);
3066
3067 sl0 =
3068 pool_elt_at_index (sm->sid_lists,
3069 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3070
3071 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
3072 (vec_len (sl0->rewrite) + b0->current_data));
3073
3074 ip0_encap = vlib_buffer_get_current (b0);
3075 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3076 IP_PROTOCOL_IPV6_ROUTE);
3077 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3078
3079 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3080 sl0->rewrite, vec_len (sl0->rewrite));
3081 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3082
3083 ip0 = vlib_buffer_get_current (b0);
3084
3085 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3086
3087 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3088 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3089 {
3090 sr_policy_rewrite_trace_t *tr =
3091 vlib_add_trace (vm, node, b0, sizeof (*tr));
3092 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3093 sizeof (tr->src.as_u8));
3094 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3095 sizeof (tr->dst.as_u8));
3096 }
3097
3098 encap_pkts++;
3099 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3100 n_left_to_next, bi0, next0);
3101 }
3102
3103 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3104 }
3105
3106 /* Update counters */
3107 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3108 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3109 encap_pkts);
3110 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3111 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3112 bsid_pkts);
3113
3114 return from_frame->n_vectors;
3115}
3116
3117/* *INDENT-OFF* */
3118VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3119 .function = sr_policy_rewrite_b_encaps,
3120 .name = "sr-pl-rewrite-b-encaps",
3121 .vector_size = sizeof (u32),
3122 .format_trace = format_sr_policy_rewrite_trace,
3123 .type = VLIB_NODE_TYPE_INTERNAL,
3124 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3125 .error_strings = sr_policy_rewrite_error_strings,
3126 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3127 .next_nodes = {
3128#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3129 foreach_sr_policy_rewrite_next
3130#undef _
3131 },
3132};
3133/* *INDENT-ON* */
3134
3135/*************************** SR Segment Lists DPOs ****************************/
3136static u8 *
3137format_sr_segment_list_dpo (u8 * s, va_list * args)
3138{
3139 ip6_sr_main_t *sm = &sr_main;
3140 ip6_address_t *addr;
3141 ip6_sr_sl_t *sl;
3142
3143 index_t index = va_arg (*args, index_t);
3144 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3145 s = format (s, "SR: Segment List index:[%d]", index);
3146 s = format (s, "\n\tSegments:");
3147
3148 sl = pool_elt_at_index (sm->sid_lists, index);
3149
3150 s = format (s, "< ");
3151 vec_foreach (addr, sl->segments)
3152 {
3153 s = format (s, "%U, ", format_ip6_address, addr);
3154 }
3155 s = format (s, "\b\b > - ");
3156 s = format (s, "Weight: %u", sl->weight);
3157
3158 return s;
3159}
3160
3161const static dpo_vft_t sr_policy_rewrite_vft = {
3162 .dv_lock = sr_dpo_lock,
3163 .dv_unlock = sr_dpo_unlock,
3164 .dv_format = format_sr_segment_list_dpo,
3165};
3166
3167const static char *const sr_pr_encaps_ip6_nodes[] = {
3168 "sr-pl-rewrite-encaps",
3169 NULL,
3170};
3171
3172const static char *const sr_pr_encaps_ip4_nodes[] = {
3173 "sr-pl-rewrite-encaps-v4",
3174 NULL,
3175};
3176
3177const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3178 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3179 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3180};
3181
3182const static char *const sr_pr_insert_ip6_nodes[] = {
3183 "sr-pl-rewrite-insert",
3184 NULL,
3185};
3186
3187const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3188 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3189};
3190
3191const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3192 "sr-pl-rewrite-b-insert",
3193 NULL,
3194};
3195
3196const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3197 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3198};
3199
3200const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3201 "sr-pl-rewrite-b-encaps",
3202 NULL,
3203};
3204
3205const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3206 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3207};
3208
3209/********************* SR Policy Rewrite initialization ***********************/
3210/**
3211 * @brief SR Policy Rewrite initialization
3212 */
3213clib_error_t *
3214sr_policy_rewrite_init (vlib_main_t * vm)
3215{
3216 ip6_sr_main_t *sm = &sr_main;
3217
3218 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3219 sm->sr_policy_index_by_key = hash_create_mem (0, sizeof (ip6_address_t),
3220 sizeof (uword));
3221
3222 /* Init SR VPO DPOs type */
3223 sr_pr_encaps_dpo_type =
3224 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3225
3226 sr_pr_insert_dpo_type =
3227 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3228
3229 sr_pr_bsid_encaps_dpo_type =
3230 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3231
3232 sr_pr_bsid_insert_dpo_type =
3233 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3234
3235 /* Register the L2 encaps node used in HW redirect */
3236 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3237
3238 sm->fib_table_ip6 = (u32) ~ 0;
3239 sm->fib_table_ip4 = (u32) ~ 0;
3240
3241 return 0;
3242}
3243
3244VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3245
3246
3247/*
3248* fd.io coding-style-patch-verification: ON
3249*
3250* Local Variables:
3251* eval: (c-set-style "gnu")
3252* End:
3253*/