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