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