blob: 2f90993a4be77bfc4ab89fc1e87a9fea21a7fee6 [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>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020043#include <vnet/srv6/sr.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010044#include <vnet/ip/ip.h>
Pablo Camarillo5d73eec2017-04-24 17:51:56 +020045#include <vnet/srv6/sr_packet.h>
Pablo Camarillofb380952016-12-07 18:34:18 +010046#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;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100352 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100353 load_balance_path_t *ip4_path_vector = 0;
354 load_balance_path_t *ip6_path_vector = 0;
355 load_balance_path_t *b_path_vector = 0;
356
357 /* In case LB does not exist, create it */
358 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
359 {
360 fib_prefix_t pfx = {
361 .fp_proto = FIB_PROTOCOL_IP6,
362 .fp_len = 128,
363 .fp_addr = {
364 .ip6 = sr_policy->bsid,
365 }
366 };
367
368 /* Add FIB entry for BSID */
369 fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
370 dpo_proto_to_fib (DPO_PROTO_IP6));
371
372 dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
373 load_balance_create (0, DPO_PROTO_IP6, fhc));
374
375 dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
376 load_balance_create (0, DPO_PROTO_IP6, fhc));
377
378 /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
Neale Ranns107e7d42017-04-11 09:55:19 -0700379 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
380 sr_policy->fib_table),
381 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100382 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;
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100450 path.path_index = FIB_NODE_INDEX_INVALID;
Pablo Camarillofb380952016-12-07 18:34:18 +0100451 load_balance_path_t *b_path_vector = 0;
452 load_balance_path_t *ip6_path_vector = 0;
453 load_balance_path_t *ip4_path_vector = 0;
454
455 /* In case LB does not exist, create it */
456 if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
457 {
458 dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
459 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
460
461 dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
462 DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
463
464 /* Update FIB entry's DPO to point to SR without LB */
465 fib_prefix_t pfx = {
466 .fp_proto = FIB_PROTOCOL_IP6,
467 .fp_len = 128,
468 .fp_addr = {
469 .ip6 = sr_policy->bsid,
470 }
471 };
Neale Ranns107e7d42017-04-11 09:55:19 -0700472 fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
473 sr_policy->fib_table),
474 &pfx, FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100475 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);
Pablo Camarillofb380952016-12-07 18:34:18 +0100519}
520
521/******************************* SR rewrite API *******************************/
522/* Three functions for handling sr policies:
523 * -> sr_policy_add
524 * -> sr_policy_del
525 * -> sr_policy_mod
526 * All of them are API. CLI function on sr_policy_command_fn */
527
528/**
529 * @brief Create a new SR policy
530 *
531 * @param bsid is the bindingSID of the SR Policy
532 * @param segments is a vector of IPv6 address composing the segment list
533 * @param weight is the weight of the sid list. optional.
534 * @param behavior is the behavior of the SR policy. (default//spray)
535 * @param fib_table is the VRF where to install the FIB entry for the BSID
536 * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
537 *
538 * @return 0 if correct, else error
539 */
540int
541sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments,
542 u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
543{
544 ip6_sr_main_t *sm = &sr_main;
545 ip6_sr_policy_t *sr_policy = 0;
Pablo Camarillofb380952016-12-07 18:34:18 +0100546 uword *p;
547
548 /* Search for existing keys (BSID) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100549 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100550 if (p)
551 {
552 /* Add SR policy that already exists; complain */
553 return -12;
554 }
555
556 /* Search collision in FIB entries */
557 /* Explanation: It might be possible that some other entity has already
558 * created a route for the BSID. This in theory is impossible, but in
559 * practise we could see it. Assert it and scream if needed */
560 fib_prefix_t pfx = {
561 .fp_proto = FIB_PROTOCOL_IP6,
562 .fp_len = 128,
563 .fp_addr = {
564 .ip6 = *bsid,
565 }
566 };
567
568 /* Lookup the FIB index associated to the table selected */
Neale Ranns107e7d42017-04-11 09:55:19 -0700569 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
570 (fib_table != (u32) ~ 0 ? fib_table : 0));
Pablo Camarillofb380952016-12-07 18:34:18 +0100571 if (fib_index == ~0)
572 return -13;
573
574 /* Lookup whether there exists an entry for the BSID */
575 fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
576 if (FIB_NODE_INDEX_INVALID != fei)
577 return -12; //There is an entry for such lookup
578
579 /* Add an SR policy object */
580 pool_get (sm->sr_policies, sr_policy);
581 memset (sr_policy, 0, sizeof (*sr_policy));
582 clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
583 sr_policy->type = behavior;
584 sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
585 sr_policy->is_encap = is_encap;
586
587 /* Copy the key */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100588 mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
589 NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100590
591 /* Create a segment list and add the index to the SR policy */
592 create_sl (sr_policy, segments, weight, is_encap);
593
594 /* If FIB doesnt exist, create them */
595 if (sm->fib_table_ip6 == (u32) ~ 0)
596 {
597 sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700598 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100599 "SRv6 steering of IP6 prefixes through BSIDs");
600 sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
Neale Ranns15002542017-09-10 04:39:11 -0700601 FIB_SOURCE_SR,
Pablo Camarillofb380952016-12-07 18:34:18 +0100602 "SRv6 steering of IP4 prefixes through BSIDs");
Pablo Camarillofb380952016-12-07 18:34:18 +0100603 }
604
605 /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
606 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
607 update_lb (sr_policy);
608 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
609 update_replicate (sr_policy);
610 return 0;
611}
612
613/**
614 * @brief Delete a SR policy
615 *
616 * @param bsid is the bindingSID of the SR Policy
617 * @param index is the index of the SR policy
618 *
619 * @return 0 if correct, else error
620 */
621int
622sr_policy_del (ip6_address_t * bsid, u32 index)
623{
624 ip6_sr_main_t *sm = &sr_main;
625 ip6_sr_policy_t *sr_policy = 0;
626 ip6_sr_sl_t *segment_list;
Pablo Camarillofb380952016-12-07 18:34:18 +0100627 u32 *sl_index;
628 uword *p;
629
Pablo Camarillofb380952016-12-07 18:34:18 +0100630 if (bsid)
631 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100632 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100633 if (p)
634 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
635 else
636 return -1;
637 }
638 else
639 {
640 sr_policy = pool_elt_at_index (sm->sr_policies, index);
641 if (!sr_policy)
642 return -1;
643 }
644
645 /* Remove BindingSID FIB entry */
646 fib_prefix_t pfx = {
647 .fp_proto = FIB_PROTOCOL_IP6,
648 .fp_len = 128,
649 .fp_addr = {
650 .ip6 = sr_policy->bsid,
651 }
652 ,
653 };
654
Neale Ranns107e7d42017-04-11 09:55:19 -0700655 fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
656 sr_policy->fib_table),
Pablo Camarillofb380952016-12-07 18:34:18 +0100657 &pfx, FIB_SOURCE_SR);
658
659 fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
660
661 if (sr_policy->is_encap)
662 fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
663
664 if (dpo_id_is_valid (&sr_policy->bsid_dpo))
665 {
666 dpo_reset (&sr_policy->bsid_dpo);
667 dpo_reset (&sr_policy->ip4_dpo);
668 dpo_reset (&sr_policy->ip6_dpo);
669 }
670
671 /* Clean SID Lists */
672 vec_foreach (sl_index, sr_policy->segments_lists)
673 {
674 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
675 vec_free (segment_list->segments);
676 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200677 if (!sr_policy->is_encap)
678 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100679 pool_put_index (sm->sid_lists, *sl_index);
680 }
681
682 /* Remove SR policy entry */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100683 mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
Pablo Camarillofb380952016-12-07 18:34:18 +0100684 pool_put (sm->sr_policies, sr_policy);
685
686 /* If FIB empty unlock it */
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100687 if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
Pablo Camarillofb380952016-12-07 18:34:18 +0100688 {
Neale Ranns15002542017-09-10 04:39:11 -0700689 fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
690 fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
Pablo Camarillofb380952016-12-07 18:34:18 +0100691 sm->fib_table_ip6 = (u32) ~ 0;
692 sm->fib_table_ip4 = (u32) ~ 0;
693 }
694
695 return 0;
696}
697
698/**
699 * @brief Modify an existing SR policy
700 *
701 * The possible modifications are adding a new Segment List, modifying an
702 * existing Segment List (modify the weight only) and delete a given
703 * Segment List from the SR Policy.
704 *
705 * @param bsid is the bindingSID of the SR Policy
706 * @param index is the index of the SR policy
707 * @param fib_table is the VRF where to install the FIB entry for the BSID
708 * @param operation is the operation to perform (among the top ones)
709 * @param segments is a vector of IPv6 address composing the segment list
710 * @param sl_index is the index of the Segment List to modify/delete
711 * @param weight is the weight of the sid list. optional.
712 * @param is_encap Mode. Encapsulation or SRH insertion.
713 *
714 * @return 0 if correct, else error
715 */
716int
717sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
718 u8 operation, ip6_address_t * segments, u32 sl_index,
719 u32 weight)
720{
721 ip6_sr_main_t *sm = &sr_main;
722 ip6_sr_policy_t *sr_policy = 0;
723 ip6_sr_sl_t *segment_list;
724 u32 *sl_index_iterate;
725 uword *p;
726
727 if (bsid)
728 {
Pablo Camarillo4521afa2017-03-16 10:43:05 +0100729 p = mhash_get (&sm->sr_policies_index_hash, bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100730 if (p)
731 sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
732 else
733 return -1;
734 }
735 else
736 {
737 sr_policy = pool_elt_at_index (sm->sr_policies, index);
738 if (!sr_policy)
739 return -1;
740 }
741
742 if (operation == 1) /* Add SR List to an existing SR policy */
743 {
744 /* Create the new SL */
745 segment_list =
746 create_sl (sr_policy, segments, weight, sr_policy->is_encap);
747
748 /* Create a new LB DPO */
749 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
750 update_lb (sr_policy);
751 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
752 update_replicate (sr_policy);
753 }
754 else if (operation == 2) /* Delete SR List from an existing SR policy */
755 {
756 /* Check that currently there are more than one SID list */
757 if (vec_len (sr_policy->segments_lists) == 1)
758 return -21;
759
760 /* Check that the SR list does exist and is assigned to the sr policy */
761 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
762 if (*sl_index_iterate == sl_index)
763 break;
764
765 if (*sl_index_iterate != sl_index)
766 return -22;
767
768 /* Remove the lucky SR list that is being kicked out */
769 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
770 vec_free (segment_list->segments);
771 vec_free (segment_list->rewrite);
Kris Michielsen91074432017-06-22 13:00:20 +0200772 if (!sr_policy->is_encap)
773 vec_free (segment_list->rewrite_bsid);
Pablo Camarillofb380952016-12-07 18:34:18 +0100774 pool_put_index (sm->sid_lists, sl_index);
775 vec_del1 (sr_policy->segments_lists,
776 sl_index_iterate - sr_policy->segments_lists);
777
778 /* Create a new LB DPO */
779 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
780 update_lb (sr_policy);
781 else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
782 update_replicate (sr_policy);
783 }
784 else if (operation == 3) /* Modify the weight of an existing SR List */
785 {
786 /* Find the corresponding SL */
787 vec_foreach (sl_index_iterate, sr_policy->segments_lists)
788 if (*sl_index_iterate == sl_index)
789 break;
790
791 if (*sl_index_iterate != sl_index)
792 return -32;
793
794 /* Change the weight */
795 segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
796 segment_list->weight = weight;
797
798 /* Update LB */
799 if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
800 update_lb (sr_policy);
801 }
802 else /* Incorrect op. */
803 return -1;
804
805 return 0;
806}
807
808/**
809 * @brief CLI for 'sr policies' command family
810 */
811static clib_error_t *
812sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
813 vlib_cli_command_t * cmd)
814{
815 int rv = -1;
816 char is_del = 0, is_add = 0, is_mod = 0;
817 char policy_set = 0;
818 ip6_address_t bsid, next_address;
819 u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
820 u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
821 ip6_address_t *segments = 0, *this_seg;
822 u8 operation = 0;
823 char is_encap = 1;
824 char is_spray = 0;
825
826 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827 {
828 if (!is_add && !is_mod && !is_del && unformat (input, "add"))
829 is_add = 1;
830 else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
831 is_del = 1;
832 else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
833 is_mod = 1;
834 else if (!policy_set
835 && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
836 policy_set = 1;
837 else if (!is_add && !policy_set
838 && unformat (input, "index %d", &sr_policy_index))
839 policy_set = 1;
840 else if (unformat (input, "weight %d", &weight));
841 else
842 if (unformat (input, "next %U", unformat_ip6_address, &next_address))
843 {
844 vec_add2 (segments, this_seg, 1);
845 clib_memcpy (this_seg->as_u8, next_address.as_u8,
846 sizeof (*this_seg));
847 }
848 else if (unformat (input, "add sl"))
849 operation = 1;
850 else if (unformat (input, "del sl index %d", &sl_index))
851 operation = 2;
852 else if (unformat (input, "mod sl index %d", &sl_index))
853 operation = 3;
854 else if (fib_table == (u32) ~ 0
855 && unformat (input, "fib-table %d", &fib_table));
856 else if (unformat (input, "encap"))
857 is_encap = 1;
858 else if (unformat (input, "insert"))
859 is_encap = 0;
860 else if (unformat (input, "spray"))
861 is_spray = 1;
862 else
863 break;
864 }
865
866 if (!is_add && !is_mod && !is_del)
867 return clib_error_return (0, "Incorrect CLI");
868
869 if (!policy_set)
870 return clib_error_return (0, "No SR policy BSID or index specified");
871
872 if (is_add)
873 {
874 if (vec_len (segments) == 0)
875 return clib_error_return (0, "No Segment List specified");
876 rv = sr_policy_add (&bsid, segments, weight,
877 (is_spray ? SR_POLICY_TYPE_SPRAY :
878 SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
879 }
880 else if (is_del)
881 rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
882 sr_policy_index);
883 else if (is_mod)
884 {
885 if (!operation)
886 return clib_error_return (0, "No SL modification specified");
887 if (operation != 1 && sl_index == (u32) ~ 0)
888 return clib_error_return (0, "No Segment List index specified");
889 if (operation == 1 && vec_len (segments) == 0)
890 return clib_error_return (0, "No Segment List specified");
891 if (operation == 3 && weight == (u32) ~ 0)
892 return clib_error_return (0, "No new weight for the SL specified");
893 rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
894 sr_policy_index, fib_table, operation, segments,
895 sl_index, weight);
896 }
897
898 switch (rv)
899 {
900 case 0:
901 break;
902 case 1:
903 return 0;
904 case -12:
905 return clib_error_return (0,
906 "There is already a FIB entry for the BindingSID address.\n"
907 "The SR policy could not be created.");
908 case -13:
909 return clib_error_return (0, "The specified FIB table does not exist.");
910 case -21:
911 return clib_error_return (0,
912 "The selected SR policy only contains ONE segment list. "
913 "Please remove the SR policy instead");
914 case -22:
915 return clib_error_return (0,
916 "Could not delete the segment list. "
917 "It is not associated with that SR policy.");
918 case -32:
919 return clib_error_return (0,
920 "Could not modify the segment list. "
921 "The given SL is not associated with such SR policy.");
922 default:
923 return clib_error_return (0, "BUG: sr policy returns %d", rv);
924 }
925 return 0;
926}
927
928/* *INDENT-OFF* */
929VLIB_CLI_COMMAND (sr_policy_command, static) = {
930 .path = "sr policy",
931 .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
932 "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
933 .long_help =
934 "Manipulation of SR policies.\n"
935 "A Segment Routing policy may contain several SID lists. Each SID list has\n"
936 "an associated weight (default 1), which will result in wECMP (uECMP).\n"
937 "Segment Routing policies might be of type encapsulation or srh insertion\n"
938 "Each SR policy will be associated with a unique BindingSID.\n"
939 "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
940 "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
941 "The add command will create a SR policy with its first segment list (sl)\n"
942 "The mod command allows you to add, remove, or modify the existing segment lists\n"
943 "within an SR policy.\n"
944 "The del command allows you to delete a SR policy along with all its associated\n"
945 "SID lists.\n",
946 .function = sr_policy_command_fn,
947};
948/* *INDENT-ON* */
949
950/**
951 * @brief CLI to display onscreen all the SR policies
952 */
953static clib_error_t *
954show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
955 vlib_cli_command_t * cmd)
956{
957 ip6_sr_main_t *sm = &sr_main;
958 u32 *sl_index;
959 ip6_sr_sl_t *segment_list = 0;
960 ip6_sr_policy_t *sr_policy = 0;
961 ip6_sr_policy_t **vec_policies = 0;
962 ip6_address_t *addr;
963 u8 *s;
964 int i = 0;
965
966 vlib_cli_output (vm, "SR policies:");
967
968 /* *INDENT-OFF* */
969 pool_foreach (sr_policy, sm->sr_policies,
970 {vec_add1 (vec_policies, sr_policy); } );
971 /* *INDENT-ON* */
972
973 vec_foreach_index (i, vec_policies)
974 {
975 sr_policy = vec_policies[i];
976 vlib_cli_output (vm, "[%u].-\tBSID: %U",
977 (u32) (sr_policy - sm->sr_policies),
978 format_ip6_address, &sr_policy->bsid);
979 vlib_cli_output (vm, "\tBehavior: %s",
980 (sr_policy->is_encap ? "Encapsulation" :
981 "SRH insertion"));
982 vlib_cli_output (vm, "\tType: %s",
983 (sr_policy->type ==
984 SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
985 vlib_cli_output (vm, "\tFIB table: %u",
986 (sr_policy->fib_table !=
987 (u32) ~ 0 ? sr_policy->fib_table : 0));
988 vlib_cli_output (vm, "\tSegment Lists:");
989 vec_foreach (sl_index, sr_policy->segments_lists)
990 {
991 s = NULL;
992 s = format (s, "\t[%u].- ", *sl_index);
993 segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
994 s = format (s, "< ");
995 vec_foreach (addr, segment_list->segments)
996 {
997 s = format (s, "%U, ", format_ip6_address, addr);
998 }
999 s = format (s, "\b\b > ");
1000 s = format (s, "weight: %u", segment_list->weight);
1001 vlib_cli_output (vm, " %s", s);
1002 }
1003 vlib_cli_output (vm, "-----------");
1004 }
1005 return 0;
1006}
1007
1008/* *INDENT-OFF* */
1009VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1010 .path = "show sr policies",
1011 .short_help = "show sr policies",
1012 .function = show_sr_policies_command_fn,
1013};
1014/* *INDENT-ON* */
1015
1016/*************************** SR rewrite graph node ****************************/
1017/**
1018 * @brief Trace for the SR Policy Rewrite graph node
1019 */
1020static u8 *
1021format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1022{
1023 //TODO
1024 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1025 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1026 sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
1027
1028 s = format
1029 (s, "SR-policy-rewrite: src %U dst %U",
1030 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1031
1032 return s;
1033}
1034
1035/**
1036 * @brief IPv6 encapsulation processing as per RFC2473
1037 */
1038static_always_inline void
1039encaps_processing_v6 (vlib_node_runtime_t * node,
1040 vlib_buffer_t * b0,
1041 ip6_header_t * ip0, ip6_header_t * ip0_encap)
1042{
1043 u32 new_l0;
1044
1045 ip0_encap->hop_limit -= 1;
1046 new_l0 =
1047 ip0->payload_length + sizeof (ip6_header_t) +
1048 clib_net_to_host_u16 (ip0_encap->payload_length);
1049 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1050 ip0->ip_version_traffic_class_and_flow_label =
1051 ip0_encap->ip_version_traffic_class_and_flow_label;
1052}
1053
1054/**
1055 * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1056 */
1057static uword
1058sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
1059 vlib_frame_t * from_frame)
1060{
1061 ip6_sr_main_t *sm = &sr_main;
1062 u32 n_left_from, next_index, *from, *to_next;
1063
1064 from = vlib_frame_vector_args (from_frame);
1065 n_left_from = from_frame->n_vectors;
1066
1067 next_index = node->cached_next_index;
1068
1069 int encap_pkts = 0, bsid_pkts = 0;
1070
1071 while (n_left_from > 0)
1072 {
1073 u32 n_left_to_next;
1074
1075 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1076
1077 /* Quad - Loop */
1078 while (n_left_from >= 8 && n_left_to_next >= 4)
1079 {
1080 u32 bi0, bi1, bi2, bi3;
1081 vlib_buffer_t *b0, *b1, *b2, *b3;
1082 u32 next0, next1, next2, next3;
1083 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1084 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1085 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1086 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1087
1088 /* Prefetch next iteration. */
1089 {
1090 vlib_buffer_t *p4, *p5, *p6, *p7;
1091
1092 p4 = vlib_get_buffer (vm, from[4]);
1093 p5 = vlib_get_buffer (vm, from[5]);
1094 p6 = vlib_get_buffer (vm, from[6]);
1095 p7 = vlib_get_buffer (vm, from[7]);
1096
1097 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1098 vlib_prefetch_buffer_header (p4, LOAD);
1099 vlib_prefetch_buffer_header (p5, LOAD);
1100 vlib_prefetch_buffer_header (p6, LOAD);
1101 vlib_prefetch_buffer_header (p7, LOAD);
1102
1103 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1104 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1105 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1106 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1107 }
1108
1109 to_next[0] = bi0 = from[0];
1110 to_next[1] = bi1 = from[1];
1111 to_next[2] = bi2 = from[2];
1112 to_next[3] = bi3 = from[3];
1113 from += 4;
1114 to_next += 4;
1115 n_left_from -= 4;
1116 n_left_to_next -= 4;
1117
1118 b0 = vlib_get_buffer (vm, bi0);
1119 b1 = vlib_get_buffer (vm, bi1);
1120 b2 = vlib_get_buffer (vm, bi2);
1121 b3 = vlib_get_buffer (vm, bi3);
1122
1123 sl0 =
1124 pool_elt_at_index (sm->sid_lists,
1125 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1126 sl1 =
1127 pool_elt_at_index (sm->sid_lists,
1128 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1129 sl2 =
1130 pool_elt_at_index (sm->sid_lists,
1131 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1132 sl3 =
1133 pool_elt_at_index (sm->sid_lists,
1134 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1135
shwethabe146f132017-03-09 16:58:26 +00001136 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1137 vec_len (sl0->rewrite));
1138 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1139 vec_len (sl1->rewrite));
1140 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1141 vec_len (sl2->rewrite));
1142 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1143 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001144
1145 ip0_encap = vlib_buffer_get_current (b0);
1146 ip1_encap = vlib_buffer_get_current (b1);
1147 ip2_encap = vlib_buffer_get_current (b2);
1148 ip3_encap = vlib_buffer_get_current (b3);
1149
1150 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1151 sl0->rewrite, vec_len (sl0->rewrite));
1152 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1153 sl1->rewrite, vec_len (sl1->rewrite));
1154 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1155 sl2->rewrite, vec_len (sl2->rewrite));
1156 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1157 sl3->rewrite, vec_len (sl3->rewrite));
1158
1159 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1160 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1161 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1162 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1163
1164 ip0 = vlib_buffer_get_current (b0);
1165 ip1 = vlib_buffer_get_current (b1);
1166 ip2 = vlib_buffer_get_current (b2);
1167 ip3 = vlib_buffer_get_current (b3);
1168
1169 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1170 encaps_processing_v6 (node, b1, ip1, ip1_encap);
1171 encaps_processing_v6 (node, b2, ip2, ip2_encap);
1172 encaps_processing_v6 (node, b3, ip3, ip3_encap);
1173
1174 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1175 {
1176 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1177 {
1178 sr_policy_rewrite_trace_t *tr =
1179 vlib_add_trace (vm, node, b0, sizeof (*tr));
1180 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1181 sizeof (tr->src.as_u8));
1182 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1183 sizeof (tr->dst.as_u8));
1184 }
1185
1186 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1187 {
1188 sr_policy_rewrite_trace_t *tr =
1189 vlib_add_trace (vm, node, b1, sizeof (*tr));
1190 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1191 sizeof (tr->src.as_u8));
1192 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1193 sizeof (tr->dst.as_u8));
1194 }
1195
1196 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1197 {
1198 sr_policy_rewrite_trace_t *tr =
1199 vlib_add_trace (vm, node, b2, sizeof (*tr));
1200 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1201 sizeof (tr->src.as_u8));
1202 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1203 sizeof (tr->dst.as_u8));
1204 }
1205
1206 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1207 {
1208 sr_policy_rewrite_trace_t *tr =
1209 vlib_add_trace (vm, node, b3, sizeof (*tr));
1210 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1211 sizeof (tr->src.as_u8));
1212 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1213 sizeof (tr->dst.as_u8));
1214 }
1215 }
1216
1217 encap_pkts += 4;
1218 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1219 n_left_to_next, bi0, bi1, bi2, bi3,
1220 next0, next1, next2, next3);
1221 }
1222
1223 /* Single loop for potentially the last three packets */
1224 while (n_left_from > 0 && n_left_to_next > 0)
1225 {
1226 u32 bi0;
1227 vlib_buffer_t *b0;
1228 ip6_header_t *ip0 = 0, *ip0_encap = 0;
1229 ip6_sr_sl_t *sl0;
1230 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1231
1232 bi0 = from[0];
1233 to_next[0] = bi0;
1234 from += 1;
1235 to_next += 1;
1236 n_left_from -= 1;
1237 n_left_to_next -= 1;
1238 b0 = vlib_get_buffer (vm, bi0);
1239
1240 sl0 =
1241 pool_elt_at_index (sm->sid_lists,
1242 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001243 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1244 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001245
1246 ip0_encap = vlib_buffer_get_current (b0);
1247
1248 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1249 sl0->rewrite, vec_len (sl0->rewrite));
1250 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1251
1252 ip0 = vlib_buffer_get_current (b0);
1253
1254 encaps_processing_v6 (node, b0, ip0, ip0_encap);
1255
1256 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1257 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1258 {
1259 sr_policy_rewrite_trace_t *tr =
1260 vlib_add_trace (vm, node, b0, sizeof (*tr));
1261 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1262 sizeof (tr->src.as_u8));
1263 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1264 sizeof (tr->dst.as_u8));
1265 }
1266
1267 encap_pkts++;
1268 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1269 n_left_to_next, bi0, next0);
1270 }
1271
1272 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1273 }
1274
1275 /* Update counters */
1276 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1277 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1278 encap_pkts);
1279 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1280 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1281 bsid_pkts);
1282
1283 return from_frame->n_vectors;
1284}
1285
1286/* *INDENT-OFF* */
1287VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
1288 .function = sr_policy_rewrite_encaps,
1289 .name = "sr-pl-rewrite-encaps",
1290 .vector_size = sizeof (u32),
1291 .format_trace = format_sr_policy_rewrite_trace,
1292 .type = VLIB_NODE_TYPE_INTERNAL,
1293 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1294 .error_strings = sr_policy_rewrite_error_strings,
1295 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1296 .next_nodes = {
1297#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1298 foreach_sr_policy_rewrite_next
1299#undef _
1300 },
1301};
1302/* *INDENT-ON* */
1303
1304/**
1305 * @brief IPv4 encapsulation processing as per RFC2473
1306 */
1307static_always_inline void
1308encaps_processing_v4 (vlib_node_runtime_t * node,
1309 vlib_buffer_t * b0,
1310 ip6_header_t * ip0, ip4_header_t * ip0_encap)
1311{
1312 u32 new_l0;
1313 ip6_sr_header_t *sr0;
1314
1315 u32 checksum0;
1316
1317 /* Inner IPv4: Decrement TTL & update checksum */
1318 ip0_encap->ttl -= 1;
1319 checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1320 checksum0 += checksum0 >= 0xffff;
1321 ip0_encap->checksum = checksum0;
1322
1323 /* Outer IPv6: Update length, FL, proto */
1324 new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1325 ip0->payload_length = clib_host_to_net_u16 (new_l0);
1326 ip0->ip_version_traffic_class_and_flow_label =
1327 clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1328 ((ip0_encap->tos & 0xFF) << 20));
1329 sr0 = (void *) (ip0 + 1);
1330 sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1331}
1332
1333/**
1334 * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1335 */
1336static uword
1337sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
1338 vlib_frame_t * from_frame)
1339{
1340 ip6_sr_main_t *sm = &sr_main;
1341 u32 n_left_from, next_index, *from, *to_next;
1342
1343 from = vlib_frame_vector_args (from_frame);
1344 n_left_from = from_frame->n_vectors;
1345
1346 next_index = node->cached_next_index;
1347
1348 int encap_pkts = 0, bsid_pkts = 0;
1349
1350 while (n_left_from > 0)
1351 {
1352 u32 n_left_to_next;
1353
1354 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1355
1356 /* Quad - Loop */
1357 while (n_left_from >= 8 && n_left_to_next >= 4)
1358 {
1359 u32 bi0, bi1, bi2, bi3;
1360 vlib_buffer_t *b0, *b1, *b2, *b3;
1361 u32 next0, next1, next2, next3;
1362 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1363 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1364 ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1365 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1366
1367 /* Prefetch next iteration. */
1368 {
1369 vlib_buffer_t *p4, *p5, *p6, *p7;
1370
1371 p4 = vlib_get_buffer (vm, from[4]);
1372 p5 = vlib_get_buffer (vm, from[5]);
1373 p6 = vlib_get_buffer (vm, from[6]);
1374 p7 = vlib_get_buffer (vm, from[7]);
1375
1376 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1377 vlib_prefetch_buffer_header (p4, LOAD);
1378 vlib_prefetch_buffer_header (p5, LOAD);
1379 vlib_prefetch_buffer_header (p6, LOAD);
1380 vlib_prefetch_buffer_header (p7, LOAD);
1381
1382 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1383 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1384 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1385 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1386 }
1387
1388 to_next[0] = bi0 = from[0];
1389 to_next[1] = bi1 = from[1];
1390 to_next[2] = bi2 = from[2];
1391 to_next[3] = bi3 = from[3];
1392 from += 4;
1393 to_next += 4;
1394 n_left_from -= 4;
1395 n_left_to_next -= 4;
1396
1397 b0 = vlib_get_buffer (vm, bi0);
1398 b1 = vlib_get_buffer (vm, bi1);
1399 b2 = vlib_get_buffer (vm, bi2);
1400 b3 = vlib_get_buffer (vm, bi3);
1401
1402 sl0 =
1403 pool_elt_at_index (sm->sid_lists,
1404 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1405 sl1 =
1406 pool_elt_at_index (sm->sid_lists,
1407 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1408 sl2 =
1409 pool_elt_at_index (sm->sid_lists,
1410 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1411 sl3 =
1412 pool_elt_at_index (sm->sid_lists,
1413 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001414 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1415 vec_len (sl0->rewrite));
1416 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1417 vec_len (sl1->rewrite));
1418 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1419 vec_len (sl2->rewrite));
1420 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1421 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001422
1423 ip0_encap = vlib_buffer_get_current (b0);
1424 ip1_encap = vlib_buffer_get_current (b1);
1425 ip2_encap = vlib_buffer_get_current (b2);
1426 ip3_encap = vlib_buffer_get_current (b3);
1427
1428 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1429 sl0->rewrite, vec_len (sl0->rewrite));
1430 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1431 sl1->rewrite, vec_len (sl1->rewrite));
1432 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1433 sl2->rewrite, vec_len (sl2->rewrite));
1434 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1435 sl3->rewrite, vec_len (sl3->rewrite));
1436
1437 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1438 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1439 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1440 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1441
1442 ip0 = vlib_buffer_get_current (b0);
1443 ip1 = vlib_buffer_get_current (b1);
1444 ip2 = vlib_buffer_get_current (b2);
1445 ip3 = vlib_buffer_get_current (b3);
1446
1447 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1448 encaps_processing_v4 (node, b1, ip1, ip1_encap);
1449 encaps_processing_v4 (node, b2, ip2, ip2_encap);
1450 encaps_processing_v4 (node, b3, ip3, ip3_encap);
1451
1452 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1453 {
1454 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1455 {
1456 sr_policy_rewrite_trace_t *tr =
1457 vlib_add_trace (vm, node, b0, sizeof (*tr));
1458 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1459 sizeof (tr->src.as_u8));
1460 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1461 sizeof (tr->dst.as_u8));
1462 }
1463
1464 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1465 {
1466 sr_policy_rewrite_trace_t *tr =
1467 vlib_add_trace (vm, node, b1, sizeof (*tr));
1468 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1469 sizeof (tr->src.as_u8));
1470 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1471 sizeof (tr->dst.as_u8));
1472 }
1473
1474 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1475 {
1476 sr_policy_rewrite_trace_t *tr =
1477 vlib_add_trace (vm, node, b2, sizeof (*tr));
1478 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1479 sizeof (tr->src.as_u8));
1480 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1481 sizeof (tr->dst.as_u8));
1482 }
1483
1484 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1485 {
1486 sr_policy_rewrite_trace_t *tr =
1487 vlib_add_trace (vm, node, b3, sizeof (*tr));
1488 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1489 sizeof (tr->src.as_u8));
1490 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1491 sizeof (tr->dst.as_u8));
1492 }
1493 }
1494
1495 encap_pkts += 4;
1496 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1497 n_left_to_next, bi0, bi1, bi2, bi3,
1498 next0, next1, next2, next3);
1499 }
1500
1501 /* Single loop for potentially the last three packets */
1502 while (n_left_from > 0 && n_left_to_next > 0)
1503 {
1504 u32 bi0;
1505 vlib_buffer_t *b0;
1506 ip6_header_t *ip0 = 0;
1507 ip4_header_t *ip0_encap = 0;
1508 ip6_sr_sl_t *sl0;
1509 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1510
1511 bi0 = from[0];
1512 to_next[0] = bi0;
1513 from += 1;
1514 to_next += 1;
1515 n_left_from -= 1;
1516 n_left_to_next -= 1;
1517 b0 = vlib_get_buffer (vm, bi0);
1518
1519 sl0 =
1520 pool_elt_at_index (sm->sid_lists,
1521 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001522 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1523 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001524
1525 ip0_encap = vlib_buffer_get_current (b0);
1526
1527 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1528 sl0->rewrite, vec_len (sl0->rewrite));
1529 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1530
1531 ip0 = vlib_buffer_get_current (b0);
1532
1533 encaps_processing_v4 (node, b0, ip0, ip0_encap);
1534
1535 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1536 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1537 {
1538 sr_policy_rewrite_trace_t *tr =
1539 vlib_add_trace (vm, node, b0, sizeof (*tr));
1540 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1541 sizeof (tr->src.as_u8));
1542 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1543 sizeof (tr->dst.as_u8));
1544 }
1545
1546 encap_pkts++;
1547 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1548 n_left_to_next, bi0, next0);
1549 }
1550
1551 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1552 }
1553
1554 /* Update counters */
1555 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1556 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1557 encap_pkts);
1558 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1559 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1560 bsid_pkts);
1561
1562 return from_frame->n_vectors;
1563}
1564
1565/* *INDENT-OFF* */
1566VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
1567 .function = sr_policy_rewrite_encaps_v4,
1568 .name = "sr-pl-rewrite-encaps-v4",
1569 .vector_size = sizeof (u32),
1570 .format_trace = format_sr_policy_rewrite_trace,
1571 .type = VLIB_NODE_TYPE_INTERNAL,
1572 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1573 .error_strings = sr_policy_rewrite_error_strings,
1574 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1575 .next_nodes = {
1576#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1577 foreach_sr_policy_rewrite_next
1578#undef _
1579 },
1580};
1581/* *INDENT-ON* */
1582
1583always_inline u32
1584ip_flow_hash (void *data)
1585{
1586 ip4_header_t *iph = (ip4_header_t *) data;
1587
1588 if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1589 return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
1590 else
1591 return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
1592}
1593
1594always_inline u64
1595mac_to_u64 (u8 * m)
1596{
1597 return (*((u64 *) m) & 0xffffffffffff);
1598}
1599
1600always_inline u32
1601l2_flow_hash (vlib_buffer_t * b0)
1602{
1603 ethernet_header_t *eh;
1604 u64 a, b, c;
1605 uword is_ip, eh_size;
1606 u16 eh_type;
1607
1608 eh = vlib_buffer_get_current (b0);
1609 eh_type = clib_net_to_host_u16 (eh->type);
1610 eh_size = ethernet_buffer_header_size (b0);
1611
1612 is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1613
1614 /* since we have 2 cache lines, use them */
1615 if (is_ip)
1616 a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1617 else
1618 a = eh->type;
1619
1620 b = mac_to_u64 ((u8 *) eh->dst_address);
1621 c = mac_to_u64 ((u8 *) eh->src_address);
1622 hash_mix64 (a, b, c);
1623
1624 return (u32) c;
1625}
1626
1627/**
1628 * @brief Graph node for applying a SR policy into a L2 frame
1629 */
1630static uword
1631sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
1632 vlib_frame_t * from_frame)
1633{
1634 ip6_sr_main_t *sm = &sr_main;
1635 u32 n_left_from, next_index, *from, *to_next;
1636
1637 from = vlib_frame_vector_args (from_frame);
1638 n_left_from = from_frame->n_vectors;
1639
1640 next_index = node->cached_next_index;
1641
1642 int encap_pkts = 0, bsid_pkts = 0;
1643
1644 while (n_left_from > 0)
1645 {
1646 u32 n_left_to_next;
1647
1648 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1649
1650 /* Quad - Loop */
1651 while (n_left_from >= 8 && n_left_to_next >= 4)
1652 {
1653 u32 bi0, bi1, bi2, bi3;
1654 vlib_buffer_t *b0, *b1, *b2, *b3;
1655 u32 next0, next1, next2, next3;
1656 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1657 ethernet_header_t *en0, *en1, *en2, *en3;
1658 ip6_header_t *ip0, *ip1, *ip2, *ip3;
1659 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1660 ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1661 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1662
1663 /* Prefetch next iteration. */
1664 {
1665 vlib_buffer_t *p4, *p5, *p6, *p7;
1666
1667 p4 = vlib_get_buffer (vm, from[4]);
1668 p5 = vlib_get_buffer (vm, from[5]);
1669 p6 = vlib_get_buffer (vm, from[6]);
1670 p7 = vlib_get_buffer (vm, from[7]);
1671
1672 /* Prefetch the buffer header and packet for the N+2 loop iteration */
1673 vlib_prefetch_buffer_header (p4, LOAD);
1674 vlib_prefetch_buffer_header (p5, LOAD);
1675 vlib_prefetch_buffer_header (p6, LOAD);
1676 vlib_prefetch_buffer_header (p7, LOAD);
1677
1678 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
1679 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
1680 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
1681 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
1682 }
1683
1684 to_next[0] = bi0 = from[0];
1685 to_next[1] = bi1 = from[1];
1686 to_next[2] = bi2 = from[2];
1687 to_next[3] = bi3 = from[3];
1688 from += 4;
1689 to_next += 4;
1690 n_left_from -= 4;
1691 n_left_to_next -= 4;
1692
1693 b0 = vlib_get_buffer (vm, bi0);
1694 b1 = vlib_get_buffer (vm, bi1);
1695 b2 = vlib_get_buffer (vm, bi2);
1696 b3 = vlib_get_buffer (vm, bi3);
1697
1698 sp0 = pool_elt_at_index (sm->sr_policies,
1699 sm->sw_iface_sr_policies[vnet_buffer
1700 (b0)->sw_if_index
1701 [VLIB_RX]]);
1702
1703 sp1 = pool_elt_at_index (sm->sr_policies,
1704 sm->sw_iface_sr_policies[vnet_buffer
1705 (b1)->sw_if_index
1706 [VLIB_RX]]);
1707
1708 sp2 = pool_elt_at_index (sm->sr_policies,
1709 sm->sw_iface_sr_policies[vnet_buffer
1710 (b2)->sw_if_index
1711 [VLIB_RX]]);
1712
1713 sp3 = pool_elt_at_index (sm->sr_policies,
1714 sm->sw_iface_sr_policies[vnet_buffer
1715 (b3)->sw_if_index
1716 [VLIB_RX]]);
1717
1718 if (vec_len (sp0->segments_lists) == 1)
1719 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1720 else
1721 {
1722 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1723 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1724 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1725 (vec_len (sp0->segments_lists) - 1))];
1726 }
1727
1728 if (vec_len (sp1->segments_lists) == 1)
1729 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1730 else
1731 {
1732 vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1733 vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1734 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1735 (vec_len (sp1->segments_lists) - 1))];
1736 }
1737
1738 if (vec_len (sp2->segments_lists) == 1)
1739 vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1740 else
1741 {
1742 vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1743 vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1744 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1745 (vec_len (sp2->segments_lists) - 1))];
1746 }
1747
1748 if (vec_len (sp3->segments_lists) == 1)
1749 vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1750 else
1751 {
1752 vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1753 vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1754 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1755 (vec_len (sp3->segments_lists) - 1))];
1756 }
1757
1758 sl0 =
1759 pool_elt_at_index (sm->sid_lists,
1760 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1761 sl1 =
1762 pool_elt_at_index (sm->sid_lists,
1763 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1764 sl2 =
1765 pool_elt_at_index (sm->sid_lists,
1766 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1767 sl3 =
1768 pool_elt_at_index (sm->sid_lists,
1769 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1770
shwethabe146f132017-03-09 16:58:26 +00001771 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1772 vec_len (sl0->rewrite));
1773 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1774 vec_len (sl1->rewrite));
1775 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1776 vec_len (sl2->rewrite));
1777 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1778 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001779
1780 en0 = vlib_buffer_get_current (b0);
1781 en1 = vlib_buffer_get_current (b1);
1782 en2 = vlib_buffer_get_current (b2);
1783 en3 = vlib_buffer_get_current (b3);
1784
1785 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1786 vec_len (sl0->rewrite));
1787 clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1788 vec_len (sl1->rewrite));
1789 clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1790 vec_len (sl2->rewrite));
1791 clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1792 vec_len (sl3->rewrite));
1793
1794 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1795 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1796 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1797 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1798
1799 ip0 = vlib_buffer_get_current (b0);
1800 ip1 = vlib_buffer_get_current (b1);
1801 ip2 = vlib_buffer_get_current (b2);
1802 ip3 = vlib_buffer_get_current (b3);
1803
1804 ip0->payload_length =
1805 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1806 ip1->payload_length =
1807 clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1808 ip2->payload_length =
1809 clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1810 ip3->payload_length =
1811 clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1812
1813 sr0 = (void *) (ip0 + 1);
1814 sr1 = (void *) (ip1 + 1);
1815 sr2 = (void *) (ip2 + 1);
1816 sr3 = (void *) (ip3 + 1);
1817
1818 sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1819 IP_PROTOCOL_IP6_NONXT;
1820
1821 /* Which Traffic class and flow label do I set ? */
1822 //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1823
1824 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1825 {
1826 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1827 {
1828 sr_policy_rewrite_trace_t *tr =
1829 vlib_add_trace (vm, node, b0, sizeof (*tr));
1830 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1831 sizeof (tr->src.as_u8));
1832 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1833 sizeof (tr->dst.as_u8));
1834 }
1835
1836 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
1837 {
1838 sr_policy_rewrite_trace_t *tr =
1839 vlib_add_trace (vm, node, b1, sizeof (*tr));
1840 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1841 sizeof (tr->src.as_u8));
1842 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1843 sizeof (tr->dst.as_u8));
1844 }
1845
1846 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
1847 {
1848 sr_policy_rewrite_trace_t *tr =
1849 vlib_add_trace (vm, node, b2, sizeof (*tr));
1850 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1851 sizeof (tr->src.as_u8));
1852 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1853 sizeof (tr->dst.as_u8));
1854 }
1855
1856 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
1857 {
1858 sr_policy_rewrite_trace_t *tr =
1859 vlib_add_trace (vm, node, b3, sizeof (*tr));
1860 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1861 sizeof (tr->src.as_u8));
1862 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1863 sizeof (tr->dst.as_u8));
1864 }
1865 }
1866
1867 encap_pkts += 4;
1868 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1869 n_left_to_next, bi0, bi1, bi2, bi3,
1870 next0, next1, next2, next3);
1871 }
1872
1873 /* Single loop for potentially the last three packets */
1874 while (n_left_from > 0 && n_left_to_next > 0)
1875 {
1876 u32 bi0;
1877 vlib_buffer_t *b0;
1878 ip6_header_t *ip0 = 0;
1879 ip6_sr_header_t *sr0;
1880 ethernet_header_t *en0;
1881 ip6_sr_policy_t *sp0;
1882 ip6_sr_sl_t *sl0;
1883 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1884
1885 bi0 = from[0];
1886 to_next[0] = bi0;
1887 from += 1;
1888 to_next += 1;
1889 n_left_from -= 1;
1890 n_left_to_next -= 1;
1891 b0 = vlib_get_buffer (vm, bi0);
1892
1893 /* Find the SR policy */
1894 sp0 = pool_elt_at_index (sm->sr_policies,
1895 sm->sw_iface_sr_policies[vnet_buffer
1896 (b0)->sw_if_index
1897 [VLIB_RX]]);
1898
1899 /* In case there is more than one SL, LB among them */
1900 if (vec_len (sp0->segments_lists) == 1)
1901 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1902 else
1903 {
1904 vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1905 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1906 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1907 (vec_len (sp0->segments_lists) - 1))];
1908 }
1909 sl0 =
1910 pool_elt_at_index (sm->sid_lists,
1911 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00001912 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
1913 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01001914
1915 en0 = vlib_buffer_get_current (b0);
1916
1917 clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1918 vec_len (sl0->rewrite));
1919
1920 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1921
1922 ip0 = vlib_buffer_get_current (b0);
1923
1924 ip0->payload_length =
1925 clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1926
1927 sr0 = (void *) (ip0 + 1);
1928 sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1929
1930 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1931 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1932 {
1933 sr_policy_rewrite_trace_t *tr =
1934 vlib_add_trace (vm, node, b0, sizeof (*tr));
1935 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1936 sizeof (tr->src.as_u8));
1937 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1938 sizeof (tr->dst.as_u8));
1939 }
1940
1941 encap_pkts++;
1942 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1943 n_left_to_next, bi0, next0);
1944 }
1945
1946 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1947 }
1948
1949 /* Update counters */
1950 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1951 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1952 encap_pkts);
1953 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
1954 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1955 bsid_pkts);
1956
1957 return from_frame->n_vectors;
1958}
1959
1960/* *INDENT-OFF* */
1961VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
1962 .function = sr_policy_rewrite_encaps_l2,
1963 .name = "sr-pl-rewrite-encaps-l2",
1964 .vector_size = sizeof (u32),
1965 .format_trace = format_sr_policy_rewrite_trace,
1966 .type = VLIB_NODE_TYPE_INTERNAL,
1967 .n_errors = SR_POLICY_REWRITE_N_ERROR,
1968 .error_strings = sr_policy_rewrite_error_strings,
1969 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1970 .next_nodes = {
1971#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1972 foreach_sr_policy_rewrite_next
1973#undef _
1974 },
1975};
1976/* *INDENT-ON* */
1977
1978/**
1979 * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1980 */
1981static uword
1982sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
1983 vlib_frame_t * from_frame)
1984{
1985 ip6_sr_main_t *sm = &sr_main;
1986 u32 n_left_from, next_index, *from, *to_next;
1987
1988 from = vlib_frame_vector_args (from_frame);
1989 n_left_from = from_frame->n_vectors;
1990
1991 next_index = node->cached_next_index;
1992
1993 int insert_pkts = 0, bsid_pkts = 0;
1994
1995 while (n_left_from > 0)
1996 {
1997 u32 n_left_to_next;
1998
1999 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2000
2001 /* Quad - Loop */
2002 while (n_left_from >= 8 && n_left_to_next >= 4)
2003 {
2004 u32 bi0, bi1, bi2, bi3;
2005 vlib_buffer_t *b0, *b1, *b2, *b3;
2006 u32 next0, next1, next2, next3;
2007 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2008 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2009 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2010 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2011 u16 new_l0, new_l1, new_l2, new_l3;
2012
2013 /* Prefetch next iteration. */
2014 {
2015 vlib_buffer_t *p4, *p5, *p6, *p7;
2016
2017 p4 = vlib_get_buffer (vm, from[4]);
2018 p5 = vlib_get_buffer (vm, from[5]);
2019 p6 = vlib_get_buffer (vm, from[6]);
2020 p7 = vlib_get_buffer (vm, from[7]);
2021
2022 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2023 vlib_prefetch_buffer_header (p4, LOAD);
2024 vlib_prefetch_buffer_header (p5, LOAD);
2025 vlib_prefetch_buffer_header (p6, LOAD);
2026 vlib_prefetch_buffer_header (p7, LOAD);
2027
2028 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2029 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2030 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2031 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2032 }
2033
2034 to_next[0] = bi0 = from[0];
2035 to_next[1] = bi1 = from[1];
2036 to_next[2] = bi2 = from[2];
2037 to_next[3] = bi3 = from[3];
2038 from += 4;
2039 to_next += 4;
2040 n_left_from -= 4;
2041 n_left_to_next -= 4;
2042
2043 b0 = vlib_get_buffer (vm, bi0);
2044 b1 = vlib_get_buffer (vm, bi1);
2045 b2 = vlib_get_buffer (vm, bi2);
2046 b3 = vlib_get_buffer (vm, bi3);
2047
2048 sl0 =
2049 pool_elt_at_index (sm->sid_lists,
2050 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2051 sl1 =
2052 pool_elt_at_index (sm->sid_lists,
2053 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2054 sl2 =
2055 pool_elt_at_index (sm->sid_lists,
2056 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2057 sl3 =
2058 pool_elt_at_index (sm->sid_lists,
2059 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002060 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2061 vec_len (sl0->rewrite));
2062 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2063 vec_len (sl1->rewrite));
2064 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2065 vec_len (sl2->rewrite));
2066 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2067 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002068
2069 ip0 = vlib_buffer_get_current (b0);
2070 ip1 = vlib_buffer_get_current (b1);
2071 ip2 = vlib_buffer_get_current (b2);
2072 ip3 = vlib_buffer_get_current (b3);
2073
2074 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2075 sr0 =
2076 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2077 ip6_ext_header_len (ip0 + 1));
2078 else
2079 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2080
2081 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2082 sr1 =
2083 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2084 ip6_ext_header_len (ip1 + 1));
2085 else
2086 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2087
2088 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2089 sr2 =
2090 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2091 ip6_ext_header_len (ip2 + 1));
2092 else
2093 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2094
2095 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2096 sr3 =
2097 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2098 ip6_ext_header_len (ip3 + 1));
2099 else
2100 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2101
2102 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2103 (void *) sr0 - (void *) ip0);
2104 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2105 (void *) sr1 - (void *) ip1);
2106 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2107 (void *) sr2 - (void *) ip2);
2108 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2109 (void *) sr3 - (void *) ip3);
2110
2111 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2112 vec_len (sl0->rewrite));
2113 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2114 vec_len (sl1->rewrite));
2115 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2116 vec_len (sl2->rewrite));
2117 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2118 vec_len (sl3->rewrite));
2119
2120 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2121 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2122 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2123 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2124
2125 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2126 ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2127 ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2128 ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2129
2130 ip0->hop_limit -= 1;
2131 ip1->hop_limit -= 1;
2132 ip2->hop_limit -= 1;
2133 ip3->hop_limit -= 1;
2134
2135 new_l0 =
2136 clib_net_to_host_u16 (ip0->payload_length) +
2137 vec_len (sl0->rewrite);
2138 new_l1 =
2139 clib_net_to_host_u16 (ip1->payload_length) +
2140 vec_len (sl1->rewrite);
2141 new_l2 =
2142 clib_net_to_host_u16 (ip2->payload_length) +
2143 vec_len (sl2->rewrite);
2144 new_l3 =
2145 clib_net_to_host_u16 (ip3->payload_length) +
2146 vec_len (sl3->rewrite);
2147
2148 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2149 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2150 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2151 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2152
2153 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2154 sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2155 sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2156 sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2157
2158 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2159 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2160 sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2161 sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2162 sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2163 sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2164 sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2165 sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2166
2167 ip0->dst_address.as_u64[0] =
2168 (sr0->segments + sr0->segments_left)->as_u64[0];
2169 ip0->dst_address.as_u64[1] =
2170 (sr0->segments + sr0->segments_left)->as_u64[1];
2171 ip1->dst_address.as_u64[0] =
2172 (sr1->segments + sr1->segments_left)->as_u64[0];
2173 ip1->dst_address.as_u64[1] =
2174 (sr1->segments + sr1->segments_left)->as_u64[1];
2175 ip2->dst_address.as_u64[0] =
2176 (sr2->segments + sr2->segments_left)->as_u64[0];
2177 ip2->dst_address.as_u64[1] =
2178 (sr2->segments + sr2->segments_left)->as_u64[1];
2179 ip3->dst_address.as_u64[0] =
2180 (sr3->segments + sr3->segments_left)->as_u64[0];
2181 ip3->dst_address.as_u64[1] =
2182 (sr3->segments + sr3->segments_left)->as_u64[1];
2183
2184 ip6_ext_header_t *ip_ext;
2185 if (ip0 + 1 == (void *) sr0)
2186 {
2187 sr0->protocol = ip0->protocol;
2188 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2189 }
2190 else
2191 {
2192 ip_ext = (void *) (ip0 + 1);
2193 sr0->protocol = ip_ext->next_hdr;
2194 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2195 }
2196
2197 if (ip1 + 1 == (void *) sr1)
2198 {
2199 sr1->protocol = ip1->protocol;
2200 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2201 }
2202 else
2203 {
2204 ip_ext = (void *) (ip2 + 1);
2205 sr2->protocol = ip_ext->next_hdr;
2206 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2207 }
2208
2209 if (ip2 + 1 == (void *) sr2)
2210 {
2211 sr2->protocol = ip2->protocol;
2212 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2213 }
2214 else
2215 {
2216 ip_ext = (void *) (ip2 + 1);
2217 sr2->protocol = ip_ext->next_hdr;
2218 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2219 }
2220
2221 if (ip3 + 1 == (void *) sr3)
2222 {
2223 sr3->protocol = ip3->protocol;
2224 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2225 }
2226 else
2227 {
2228 ip_ext = (void *) (ip3 + 1);
2229 sr3->protocol = ip_ext->next_hdr;
2230 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2231 }
2232
2233 insert_pkts += 4;
2234
2235 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2236 {
2237 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2238 {
2239 sr_policy_rewrite_trace_t *tr =
2240 vlib_add_trace (vm, node, b0, sizeof (*tr));
2241 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2242 sizeof (tr->src.as_u8));
2243 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2244 sizeof (tr->dst.as_u8));
2245 }
2246
2247 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2248 {
2249 sr_policy_rewrite_trace_t *tr =
2250 vlib_add_trace (vm, node, b1, sizeof (*tr));
2251 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2252 sizeof (tr->src.as_u8));
2253 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2254 sizeof (tr->dst.as_u8));
2255 }
2256
2257 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2258 {
2259 sr_policy_rewrite_trace_t *tr =
2260 vlib_add_trace (vm, node, b2, sizeof (*tr));
2261 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2262 sizeof (tr->src.as_u8));
2263 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2264 sizeof (tr->dst.as_u8));
2265 }
2266
2267 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2268 {
2269 sr_policy_rewrite_trace_t *tr =
2270 vlib_add_trace (vm, node, b3, sizeof (*tr));
2271 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2272 sizeof (tr->src.as_u8));
2273 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2274 sizeof (tr->dst.as_u8));
2275 }
2276 }
2277
2278 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2279 n_left_to_next, bi0, bi1, bi2, bi3,
2280 next0, next1, next2, next3);
2281 }
2282
2283 /* Single loop for potentially the last three packets */
2284 while (n_left_from > 0 && n_left_to_next > 0)
2285 {
2286 u32 bi0;
2287 vlib_buffer_t *b0;
2288 ip6_header_t *ip0 = 0;
2289 ip6_sr_header_t *sr0 = 0;
2290 ip6_sr_sl_t *sl0;
2291 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2292 u16 new_l0 = 0;
2293
2294 bi0 = from[0];
2295 to_next[0] = bi0;
2296 from += 1;
2297 to_next += 1;
2298 n_left_from -= 1;
2299 n_left_to_next -= 1;
2300
2301 b0 = vlib_get_buffer (vm, bi0);
2302 sl0 =
2303 pool_elt_at_index (sm->sid_lists,
2304 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002305 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2306 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002307
2308 ip0 = vlib_buffer_get_current (b0);
2309
2310 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2311 sr0 =
2312 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2313 ip6_ext_header_len (ip0 + 1));
2314 else
2315 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2316
2317 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2318 (void *) sr0 - (void *) ip0);
2319 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2320 vec_len (sl0->rewrite));
2321
2322 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2323
2324 ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2325 ip0->hop_limit -= 1;
2326 new_l0 =
2327 clib_net_to_host_u16 (ip0->payload_length) +
2328 vec_len (sl0->rewrite);
2329 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2330
2331 sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2332 sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2333 sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2334
2335 ip0->dst_address.as_u64[0] =
2336 (sr0->segments + sr0->segments_left)->as_u64[0];
2337 ip0->dst_address.as_u64[1] =
2338 (sr0->segments + sr0->segments_left)->as_u64[1];
2339
2340 if (ip0 + 1 == (void *) sr0)
2341 {
2342 sr0->protocol = ip0->protocol;
2343 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2344 }
2345 else
2346 {
2347 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2348 sr0->protocol = ip_ext->next_hdr;
2349 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2350 }
2351
2352 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2353 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2354 {
2355 sr_policy_rewrite_trace_t *tr =
2356 vlib_add_trace (vm, node, b0, sizeof (*tr));
2357 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2358 sizeof (tr->src.as_u8));
2359 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2360 sizeof (tr->dst.as_u8));
2361 }
2362
2363 insert_pkts++;
2364
2365 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2366 n_left_to_next, bi0, next0);
2367 }
2368
2369 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2370 }
2371
2372 /* Update counters */
2373 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2374 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2375 insert_pkts);
2376 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2377 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2378 bsid_pkts);
2379 return from_frame->n_vectors;
2380}
2381
2382/* *INDENT-OFF* */
2383VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
2384 .function = sr_policy_rewrite_insert,
2385 .name = "sr-pl-rewrite-insert",
2386 .vector_size = sizeof (u32),
2387 .format_trace = format_sr_policy_rewrite_trace,
2388 .type = VLIB_NODE_TYPE_INTERNAL,
2389 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2390 .error_strings = sr_policy_rewrite_error_strings,
2391 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2392 .next_nodes = {
2393#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2394 foreach_sr_policy_rewrite_next
2395#undef _
2396 },
2397};
2398/* *INDENT-ON* */
2399
2400/**
2401 * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2402 */
2403static uword
2404sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
2405 vlib_frame_t * from_frame)
2406{
2407 ip6_sr_main_t *sm = &sr_main;
2408 u32 n_left_from, next_index, *from, *to_next;
2409
2410 from = vlib_frame_vector_args (from_frame);
2411 n_left_from = from_frame->n_vectors;
2412
2413 next_index = node->cached_next_index;
2414
2415 int insert_pkts = 0, bsid_pkts = 0;
2416
2417 while (n_left_from > 0)
2418 {
2419 u32 n_left_to_next;
2420
2421 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2422
2423 /* Quad - Loop */
2424 while (n_left_from >= 8 && n_left_to_next >= 4)
2425 {
2426 u32 bi0, bi1, bi2, bi3;
2427 vlib_buffer_t *b0, *b1, *b2, *b3;
2428 u32 next0, next1, next2, next3;
2429 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2430 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2431 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2432 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2433 u16 new_l0, new_l1, new_l2, new_l3;
2434
2435 /* Prefetch next iteration. */
2436 {
2437 vlib_buffer_t *p4, *p5, *p6, *p7;
2438
2439 p4 = vlib_get_buffer (vm, from[4]);
2440 p5 = vlib_get_buffer (vm, from[5]);
2441 p6 = vlib_get_buffer (vm, from[6]);
2442 p7 = vlib_get_buffer (vm, from[7]);
2443
2444 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2445 vlib_prefetch_buffer_header (p4, LOAD);
2446 vlib_prefetch_buffer_header (p5, LOAD);
2447 vlib_prefetch_buffer_header (p6, LOAD);
2448 vlib_prefetch_buffer_header (p7, LOAD);
2449
2450 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2451 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2452 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2453 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2454 }
2455
2456 to_next[0] = bi0 = from[0];
2457 to_next[1] = bi1 = from[1];
2458 to_next[2] = bi2 = from[2];
2459 to_next[3] = bi3 = from[3];
2460 from += 4;
2461 to_next += 4;
2462 n_left_from -= 4;
2463 n_left_to_next -= 4;
2464
2465 b0 = vlib_get_buffer (vm, bi0);
2466 b1 = vlib_get_buffer (vm, bi1);
2467 b2 = vlib_get_buffer (vm, bi2);
2468 b3 = vlib_get_buffer (vm, bi3);
2469
2470 sl0 =
2471 pool_elt_at_index (sm->sid_lists,
2472 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2473 sl1 =
2474 pool_elt_at_index (sm->sid_lists,
2475 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2476 sl2 =
2477 pool_elt_at_index (sm->sid_lists,
2478 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2479 sl3 =
2480 pool_elt_at_index (sm->sid_lists,
2481 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002482 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2483 vec_len (sl0->rewrite_bsid));
2484 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2485 vec_len (sl1->rewrite_bsid));
2486 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2487 vec_len (sl2->rewrite_bsid));
2488 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2489 vec_len (sl3->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002490
2491 ip0 = vlib_buffer_get_current (b0);
2492 ip1 = vlib_buffer_get_current (b1);
2493 ip2 = vlib_buffer_get_current (b2);
2494 ip3 = vlib_buffer_get_current (b3);
2495
2496 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2497 sr0 =
2498 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2499 ip6_ext_header_len (ip0 + 1));
2500 else
2501 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2502
2503 if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2504 sr1 =
2505 (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2506 ip6_ext_header_len (ip1 + 1));
2507 else
2508 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2509
2510 if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2511 sr2 =
2512 (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2513 ip6_ext_header_len (ip2 + 1));
2514 else
2515 sr2 = (ip6_sr_header_t *) (ip2 + 1);
2516
2517 if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2518 sr3 =
2519 (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2520 ip6_ext_header_len (ip3 + 1));
2521 else
2522 sr3 = (ip6_sr_header_t *) (ip3 + 1);
2523
2524 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2525 (void *) sr0 - (void *) ip0);
2526 clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2527 (void *) sr1 - (void *) ip1);
2528 clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2529 (void *) sr2 - (void *) ip2);
2530 clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2531 (void *) sr3 - (void *) ip3);
2532
2533 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2534 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2535 clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2536 sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2537 clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2538 sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2539 clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2540 sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2541
2542 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2543 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2544 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2545 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2546
2547 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2548 ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2549 ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2550 ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2551
2552 ip0->hop_limit -= 1;
2553 ip1->hop_limit -= 1;
2554 ip2->hop_limit -= 1;
2555 ip3->hop_limit -= 1;
2556
2557 new_l0 =
2558 clib_net_to_host_u16 (ip0->payload_length) +
2559 vec_len (sl0->rewrite_bsid);
2560 new_l1 =
2561 clib_net_to_host_u16 (ip1->payload_length) +
2562 vec_len (sl1->rewrite_bsid);
2563 new_l2 =
2564 clib_net_to_host_u16 (ip2->payload_length) +
2565 vec_len (sl2->rewrite_bsid);
2566 new_l3 =
2567 clib_net_to_host_u16 (ip3->payload_length) +
2568 vec_len (sl3->rewrite_bsid);
2569
2570 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2571 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2572 ip2->payload_length = clib_host_to_net_u16 (new_l2);
2573 ip3->payload_length = clib_host_to_net_u16 (new_l3);
2574
2575 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2576 sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2577 sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2578 sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2579
2580 ip0->dst_address.as_u64[0] =
2581 (sr0->segments + sr0->segments_left)->as_u64[0];
2582 ip0->dst_address.as_u64[1] =
2583 (sr0->segments + sr0->segments_left)->as_u64[1];
2584 ip1->dst_address.as_u64[0] =
2585 (sr1->segments + sr1->segments_left)->as_u64[0];
2586 ip1->dst_address.as_u64[1] =
2587 (sr1->segments + sr1->segments_left)->as_u64[1];
2588 ip2->dst_address.as_u64[0] =
2589 (sr2->segments + sr2->segments_left)->as_u64[0];
2590 ip2->dst_address.as_u64[1] =
2591 (sr2->segments + sr2->segments_left)->as_u64[1];
2592 ip3->dst_address.as_u64[0] =
2593 (sr3->segments + sr3->segments_left)->as_u64[0];
2594 ip3->dst_address.as_u64[1] =
2595 (sr3->segments + sr3->segments_left)->as_u64[1];
2596
2597 ip6_ext_header_t *ip_ext;
2598 if (ip0 + 1 == (void *) sr0)
2599 {
2600 sr0->protocol = ip0->protocol;
2601 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2602 }
2603 else
2604 {
2605 ip_ext = (void *) (ip0 + 1);
2606 sr0->protocol = ip_ext->next_hdr;
2607 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2608 }
2609
2610 if (ip1 + 1 == (void *) sr1)
2611 {
2612 sr1->protocol = ip1->protocol;
2613 ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2614 }
2615 else
2616 {
2617 ip_ext = (void *) (ip2 + 1);
2618 sr2->protocol = ip_ext->next_hdr;
2619 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2620 }
2621
2622 if (ip2 + 1 == (void *) sr2)
2623 {
2624 sr2->protocol = ip2->protocol;
2625 ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2626 }
2627 else
2628 {
2629 ip_ext = (void *) (ip2 + 1);
2630 sr2->protocol = ip_ext->next_hdr;
2631 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2632 }
2633
2634 if (ip3 + 1 == (void *) sr3)
2635 {
2636 sr3->protocol = ip3->protocol;
2637 ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2638 }
2639 else
2640 {
2641 ip_ext = (void *) (ip3 + 1);
2642 sr3->protocol = ip_ext->next_hdr;
2643 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2644 }
2645
2646 insert_pkts += 4;
2647
2648 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2649 {
2650 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2651 {
2652 sr_policy_rewrite_trace_t *tr =
2653 vlib_add_trace (vm, node, b0, sizeof (*tr));
2654 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2655 sizeof (tr->src.as_u8));
2656 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2657 sizeof (tr->dst.as_u8));
2658 }
2659
2660 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2661 {
2662 sr_policy_rewrite_trace_t *tr =
2663 vlib_add_trace (vm, node, b1, sizeof (*tr));
2664 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2665 sizeof (tr->src.as_u8));
2666 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2667 sizeof (tr->dst.as_u8));
2668 }
2669
2670 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
2671 {
2672 sr_policy_rewrite_trace_t *tr =
2673 vlib_add_trace (vm, node, b2, sizeof (*tr));
2674 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2675 sizeof (tr->src.as_u8));
2676 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2677 sizeof (tr->dst.as_u8));
2678 }
2679
2680 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
2681 {
2682 sr_policy_rewrite_trace_t *tr =
2683 vlib_add_trace (vm, node, b3, sizeof (*tr));
2684 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2685 sizeof (tr->src.as_u8));
2686 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2687 sizeof (tr->dst.as_u8));
2688 }
2689 }
2690
2691 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2692 n_left_to_next, bi0, bi1, bi2, bi3,
2693 next0, next1, next2, next3);
2694 }
2695
2696 /* Single loop for potentially the last three packets */
2697 while (n_left_from > 0 && n_left_to_next > 0)
2698 {
2699 u32 bi0;
2700 vlib_buffer_t *b0;
2701 ip6_header_t *ip0 = 0;
2702 ip6_sr_header_t *sr0 = 0;
2703 ip6_sr_sl_t *sl0;
2704 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2705 u16 new_l0 = 0;
2706
2707 bi0 = from[0];
2708 to_next[0] = bi0;
2709 from += 1;
2710 to_next += 1;
2711 n_left_from -= 1;
2712 n_left_to_next -= 1;
2713
2714 b0 = vlib_get_buffer (vm, bi0);
2715 sl0 =
2716 pool_elt_at_index (sm->sid_lists,
2717 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002718 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2719 vec_len (sl0->rewrite_bsid));
Pablo Camarillofb380952016-12-07 18:34:18 +01002720
2721 ip0 = vlib_buffer_get_current (b0);
2722
2723 if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2724 sr0 =
2725 (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2726 ip6_ext_header_len (ip0 + 1));
2727 else
2728 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2729
2730 clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2731 (void *) sr0 - (void *) ip0);
2732 clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2733 sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2734
2735 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2736
2737 ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2738 ip0->hop_limit -= 1;
2739 new_l0 =
2740 clib_net_to_host_u16 (ip0->payload_length) +
2741 vec_len (sl0->rewrite_bsid);
2742 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2743
2744 sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2745
2746 ip0->dst_address.as_u64[0] =
2747 (sr0->segments + sr0->segments_left)->as_u64[0];
2748 ip0->dst_address.as_u64[1] =
2749 (sr0->segments + sr0->segments_left)->as_u64[1];
2750
2751 if (ip0 + 1 == (void *) sr0)
2752 {
2753 sr0->protocol = ip0->protocol;
2754 ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2755 }
2756 else
2757 {
2758 ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2759 sr0->protocol = ip_ext->next_hdr;
2760 ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2761 }
2762
2763 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2764 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2765 {
2766 sr_policy_rewrite_trace_t *tr =
2767 vlib_add_trace (vm, node, b0, sizeof (*tr));
2768 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2769 sizeof (tr->src.as_u8));
2770 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2771 sizeof (tr->dst.as_u8));
2772 }
2773
2774 insert_pkts++;
2775
2776 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2777 n_left_to_next, bi0, next0);
2778 }
2779
2780 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2781 }
2782
2783 /* Update counters */
2784 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2785 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2786 insert_pkts);
2787 vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
2788 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2789 bsid_pkts);
2790 return from_frame->n_vectors;
2791}
2792
2793/* *INDENT-OFF* */
2794VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
2795 .function = sr_policy_rewrite_b_insert,
2796 .name = "sr-pl-rewrite-b-insert",
2797 .vector_size = sizeof (u32),
2798 .format_trace = format_sr_policy_rewrite_trace,
2799 .type = VLIB_NODE_TYPE_INTERNAL,
2800 .n_errors = SR_POLICY_REWRITE_N_ERROR,
2801 .error_strings = sr_policy_rewrite_error_strings,
2802 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2803 .next_nodes = {
2804#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2805 foreach_sr_policy_rewrite_next
2806#undef _
2807 },
2808};
2809/* *INDENT-ON* */
2810
2811/**
2812 * @brief Function BSID encapsulation
2813 */
2814static_always_inline void
2815end_bsid_encaps_srh_processing (vlib_node_runtime_t * node,
2816 vlib_buffer_t * b0,
2817 ip6_header_t * ip0,
2818 ip6_sr_header_t * sr0, u32 * next0)
2819{
2820 ip6_address_t *new_dst0;
2821
2822 if (PREDICT_FALSE (!sr0))
2823 goto error_bsid_encaps;
2824
2825 if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
2826 {
2827 if (PREDICT_TRUE (sr0->segments_left != 0))
2828 {
2829 sr0->segments_left -= 1;
2830 new_dst0 = (ip6_address_t *) (sr0->segments);
2831 new_dst0 += sr0->segments_left;
2832 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2833 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2834 return;
2835 }
2836 }
2837
2838error_bsid_encaps:
2839 *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2840 b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2841}
2842
2843/**
2844 * @brief Graph node for applying a SR policy BSID - Encapsulation
2845 */
2846static uword
2847sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
2848 vlib_frame_t * from_frame)
2849{
2850 ip6_sr_main_t *sm = &sr_main;
2851 u32 n_left_from, next_index, *from, *to_next;
2852
2853 from = vlib_frame_vector_args (from_frame);
2854 n_left_from = from_frame->n_vectors;
2855
2856 next_index = node->cached_next_index;
2857
2858 int encap_pkts = 0, bsid_pkts = 0;
2859
2860 while (n_left_from > 0)
2861 {
2862 u32 n_left_to_next;
2863
2864 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2865
2866 /* Quad - Loop */
2867 while (n_left_from >= 8 && n_left_to_next >= 4)
2868 {
2869 u32 bi0, bi1, bi2, bi3;
2870 vlib_buffer_t *b0, *b1, *b2, *b3;
2871 u32 next0, next1, next2, next3;
2872 next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2873 ip6_header_t *ip0, *ip1, *ip2, *ip3;
2874 ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2875 ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2876 ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2877 ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2878
2879 /* Prefetch next iteration. */
2880 {
2881 vlib_buffer_t *p4, *p5, *p6, *p7;
2882
2883 p4 = vlib_get_buffer (vm, from[4]);
2884 p5 = vlib_get_buffer (vm, from[5]);
2885 p6 = vlib_get_buffer (vm, from[6]);
2886 p7 = vlib_get_buffer (vm, from[7]);
2887
2888 /* Prefetch the buffer header and packet for the N+2 loop iteration */
2889 vlib_prefetch_buffer_header (p4, LOAD);
2890 vlib_prefetch_buffer_header (p5, LOAD);
2891 vlib_prefetch_buffer_header (p6, LOAD);
2892 vlib_prefetch_buffer_header (p7, LOAD);
2893
2894 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE);
2895 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE);
2896 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE);
2897 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE);
2898 }
2899
2900 to_next[0] = bi0 = from[0];
2901 to_next[1] = bi1 = from[1];
2902 to_next[2] = bi2 = from[2];
2903 to_next[3] = bi3 = from[3];
2904 from += 4;
2905 to_next += 4;
2906 n_left_from -= 4;
2907 n_left_to_next -= 4;
2908
2909 b0 = vlib_get_buffer (vm, bi0);
2910 b1 = vlib_get_buffer (vm, bi1);
2911 b2 = vlib_get_buffer (vm, bi2);
2912 b3 = vlib_get_buffer (vm, bi3);
2913
2914 sl0 =
2915 pool_elt_at_index (sm->sid_lists,
2916 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2917 sl1 =
2918 pool_elt_at_index (sm->sid_lists,
2919 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2920 sl2 =
2921 pool_elt_at_index (sm->sid_lists,
2922 vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2923 sl3 =
2924 pool_elt_at_index (sm->sid_lists,
2925 vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00002926 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2927 vec_len (sl0->rewrite));
2928 ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2929 vec_len (sl1->rewrite));
2930 ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2931 vec_len (sl2->rewrite));
2932 ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
2933 vec_len (sl3->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01002934
2935 ip0_encap = vlib_buffer_get_current (b0);
2936 ip1_encap = vlib_buffer_get_current (b1);
2937 ip2_encap = vlib_buffer_get_current (b2);
2938 ip3_encap = vlib_buffer_get_current (b3);
2939
2940 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2941 IP_PROTOCOL_IPV6_ROUTE);
2942 ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2943 IP_PROTOCOL_IPV6_ROUTE);
2944 ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2945 IP_PROTOCOL_IPV6_ROUTE);
2946 ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2947 IP_PROTOCOL_IPV6_ROUTE);
2948
2949 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2950 end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2951 end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2952 end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2953
2954 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2955 sl0->rewrite, vec_len (sl0->rewrite));
2956 clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2957 sl1->rewrite, vec_len (sl1->rewrite));
2958 clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2959 sl2->rewrite, vec_len (sl2->rewrite));
2960 clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2961 sl3->rewrite, vec_len (sl3->rewrite));
2962
2963 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2964 vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2965 vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2966 vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2967
2968 ip0 = vlib_buffer_get_current (b0);
2969 ip1 = vlib_buffer_get_current (b1);
2970 ip2 = vlib_buffer_get_current (b2);
2971 ip3 = vlib_buffer_get_current (b3);
2972
2973 encaps_processing_v6 (node, b0, ip0, ip0_encap);
2974 encaps_processing_v6 (node, b1, ip1, ip1_encap);
2975 encaps_processing_v6 (node, b2, ip2, ip2_encap);
2976 encaps_processing_v6 (node, b3, ip3, ip3_encap);
2977
2978 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2979 {
2980 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2981 {
2982 sr_policy_rewrite_trace_t *tr =
2983 vlib_add_trace (vm, node, b0, sizeof (*tr));
2984 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2985 sizeof (tr->src.as_u8));
2986 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2987 sizeof (tr->dst.as_u8));
2988 }
2989
2990 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2991 {
2992 sr_policy_rewrite_trace_t *tr =
2993 vlib_add_trace (vm, node, b1, sizeof (*tr));
2994 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2995 sizeof (tr->src.as_u8));
2996 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2997 sizeof (tr->dst.as_u8));
2998 }
2999
3000 if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
3001 {
3002 sr_policy_rewrite_trace_t *tr =
3003 vlib_add_trace (vm, node, b2, sizeof (*tr));
3004 clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3005 sizeof (tr->src.as_u8));
3006 clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3007 sizeof (tr->dst.as_u8));
3008 }
3009
3010 if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
3011 {
3012 sr_policy_rewrite_trace_t *tr =
3013 vlib_add_trace (vm, node, b3, sizeof (*tr));
3014 clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3015 sizeof (tr->src.as_u8));
3016 clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3017 sizeof (tr->dst.as_u8));
3018 }
3019 }
3020
3021 encap_pkts += 4;
3022 vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3023 n_left_to_next, bi0, bi1, bi2, bi3,
3024 next0, next1, next2, next3);
3025 }
3026
3027 /* Single loop for potentially the last three packets */
3028 while (n_left_from > 0 && n_left_to_next > 0)
3029 {
3030 u32 bi0;
3031 vlib_buffer_t *b0;
3032 ip6_header_t *ip0 = 0, *ip0_encap = 0;
3033 ip6_ext_header_t *prev0;
3034 ip6_sr_header_t *sr0;
3035 ip6_sr_sl_t *sl0;
3036 u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3037
3038 bi0 = from[0];
3039 to_next[0] = bi0;
3040 from += 1;
3041 to_next += 1;
3042 n_left_from -= 1;
3043 n_left_to_next -= 1;
3044 b0 = vlib_get_buffer (vm, bi0);
3045
3046 sl0 =
3047 pool_elt_at_index (sm->sid_lists,
3048 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
shwethabe146f132017-03-09 16:58:26 +00003049 ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
3050 vec_len (sl0->rewrite));
Pablo Camarillofb380952016-12-07 18:34:18 +01003051
3052 ip0_encap = vlib_buffer_get_current (b0);
3053 ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3054 IP_PROTOCOL_IPV6_ROUTE);
3055 end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3056
3057 clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3058 sl0->rewrite, vec_len (sl0->rewrite));
3059 vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3060
3061 ip0 = vlib_buffer_get_current (b0);
3062
3063 encaps_processing_v6 (node, b0, ip0, ip0_encap);
3064
3065 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3066 PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3067 {
3068 sr_policy_rewrite_trace_t *tr =
3069 vlib_add_trace (vm, node, b0, sizeof (*tr));
3070 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3071 sizeof (tr->src.as_u8));
3072 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3073 sizeof (tr->dst.as_u8));
3074 }
3075
3076 encap_pkts++;
3077 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3078 n_left_to_next, bi0, next0);
3079 }
3080
3081 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3082 }
3083
3084 /* Update counters */
3085 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3086 SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3087 encap_pkts);
3088 vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
3089 SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3090 bsid_pkts);
3091
3092 return from_frame->n_vectors;
3093}
3094
3095/* *INDENT-OFF* */
3096VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
3097 .function = sr_policy_rewrite_b_encaps,
3098 .name = "sr-pl-rewrite-b-encaps",
3099 .vector_size = sizeof (u32),
3100 .format_trace = format_sr_policy_rewrite_trace,
3101 .type = VLIB_NODE_TYPE_INTERNAL,
3102 .n_errors = SR_POLICY_REWRITE_N_ERROR,
3103 .error_strings = sr_policy_rewrite_error_strings,
3104 .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3105 .next_nodes = {
3106#define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3107 foreach_sr_policy_rewrite_next
3108#undef _
3109 },
3110};
3111/* *INDENT-ON* */
3112
3113/*************************** SR Segment Lists DPOs ****************************/
3114static u8 *
3115format_sr_segment_list_dpo (u8 * s, va_list * args)
3116{
3117 ip6_sr_main_t *sm = &sr_main;
3118 ip6_address_t *addr;
3119 ip6_sr_sl_t *sl;
3120
3121 index_t index = va_arg (*args, index_t);
3122 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3123 s = format (s, "SR: Segment List index:[%d]", index);
3124 s = format (s, "\n\tSegments:");
3125
3126 sl = pool_elt_at_index (sm->sid_lists, index);
3127
3128 s = format (s, "< ");
3129 vec_foreach (addr, sl->segments)
3130 {
3131 s = format (s, "%U, ", format_ip6_address, addr);
3132 }
3133 s = format (s, "\b\b > - ");
3134 s = format (s, "Weight: %u", sl->weight);
3135
3136 return s;
3137}
3138
3139const static dpo_vft_t sr_policy_rewrite_vft = {
3140 .dv_lock = sr_dpo_lock,
3141 .dv_unlock = sr_dpo_unlock,
3142 .dv_format = format_sr_segment_list_dpo,
3143};
3144
3145const static char *const sr_pr_encaps_ip6_nodes[] = {
3146 "sr-pl-rewrite-encaps",
3147 NULL,
3148};
3149
3150const static char *const sr_pr_encaps_ip4_nodes[] = {
3151 "sr-pl-rewrite-encaps-v4",
3152 NULL,
3153};
3154
3155const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3156 [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
3157 [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
3158};
3159
3160const static char *const sr_pr_insert_ip6_nodes[] = {
3161 "sr-pl-rewrite-insert",
3162 NULL,
3163};
3164
3165const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3166 [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
3167};
3168
3169const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3170 "sr-pl-rewrite-b-insert",
3171 NULL,
3172};
3173
3174const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3175 [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
3176};
3177
3178const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3179 "sr-pl-rewrite-b-encaps",
3180 NULL,
3181};
3182
3183const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3184 [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
3185};
3186
3187/********************* SR Policy Rewrite initialization ***********************/
3188/**
3189 * @brief SR Policy Rewrite initialization
3190 */
3191clib_error_t *
3192sr_policy_rewrite_init (vlib_main_t * vm)
3193{
3194 ip6_sr_main_t *sm = &sr_main;
3195
3196 /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
Pablo Camarillo4521afa2017-03-16 10:43:05 +01003197 mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3198 sizeof (ip6_address_t));
Pablo Camarillofb380952016-12-07 18:34:18 +01003199
3200 /* Init SR VPO DPOs type */
3201 sr_pr_encaps_dpo_type =
3202 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3203
3204 sr_pr_insert_dpo_type =
3205 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3206
3207 sr_pr_bsid_encaps_dpo_type =
3208 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3209
3210 sr_pr_bsid_insert_dpo_type =
3211 dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3212
3213 /* Register the L2 encaps node used in HW redirect */
3214 sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
3215
3216 sm->fib_table_ip6 = (u32) ~ 0;
3217 sm->fib_table_ip4 = (u32) ~ 0;
3218
3219 return 0;
3220}
3221
3222VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
3223
3224
3225/*
3226* fd.io coding-style-patch-verification: ON
3227*
3228* Local Variables:
3229* eval: (c-set-style "gnu")
3230* End:
3231*/