Line data Source code
1 : /*
2 : * node.c
3 : *
4 : * Copyright (c) 2015 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 : #include <vlib/vlib.h>
19 : #include <vnet/vnet.h>
20 : #include <vppinfra/error.h>
21 : #include <srv6-ad/ad.h>
22 :
23 :
24 : /******************************* Packet tracing *******************************/
25 :
26 : typedef struct
27 : {
28 : u32 localsid_index;
29 : } srv6_ad_localsid_trace_t;
30 :
31 : typedef struct
32 : {
33 : u8 error;
34 : ip6_address_t src, dst;
35 : } srv6_ad_rewrite_trace_t;
36 :
37 : static u8 *
38 0 : format_srv6_ad_localsid_trace (u8 * s, va_list * args)
39 : {
40 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
41 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
42 0 : srv6_ad_localsid_trace_t *t = va_arg (*args, srv6_ad_localsid_trace_t *);
43 :
44 0 : return format (s, "SRv6-AD-localsid: localsid_index %d", t->localsid_index);
45 : }
46 :
47 : static u8 *
48 9 : format_srv6_ad_rewrite_trace (u8 * s, va_list * args)
49 : {
50 9 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51 9 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
52 9 : srv6_ad_rewrite_trace_t *t = va_arg (*args, srv6_ad_rewrite_trace_t *);
53 :
54 9 : if (PREDICT_FALSE (t->error != 0))
55 : {
56 0 : return format (s, "SRv6-AD-rewrite: cache is empty");
57 : }
58 :
59 9 : return format (s, "SRv6-AD-rewrite: src %U dst %U",
60 : format_ip6_address, &t->src, format_ip6_address, &t->dst);
61 : }
62 :
63 :
64 : /***************************** Nodes registration *****************************/
65 :
66 : vlib_node_registration_t srv6_ad4_rewrite_node;
67 : vlib_node_registration_t srv6_ad6_rewrite_node;
68 :
69 :
70 : /****************************** Packet counters *******************************/
71 :
72 : #define foreach_srv6_ad_rewrite_counter \
73 : _(PROCESSED, "srv6-ad rewritten packets") \
74 : _(NO_RW, "(Error) No header for rewriting.")
75 :
76 : typedef enum
77 : {
78 : #define _(sym,str) SRV6_AD_REWRITE_COUNTER_##sym,
79 : foreach_srv6_ad_rewrite_counter
80 : #undef _
81 : SRV6_AD_REWRITE_N_COUNTERS,
82 : } srv6_ad_rewrite_counters;
83 :
84 : static char *srv6_ad_rewrite_counter_strings[] = {
85 : #define _(sym,string) string,
86 : foreach_srv6_ad_rewrite_counter
87 : #undef _
88 : };
89 :
90 :
91 : /********************************* Next nodes *********************************/
92 :
93 : typedef enum
94 : {
95 : SRV6_AD_LOCALSID_NEXT_ERROR,
96 : SRV6_AD_LOCALSID_NEXT_REWRITE4,
97 : SRV6_AD_LOCALSID_NEXT_REWRITE6,
98 : SRV6_AD_LOCALSID_NEXT_INTERFACE,
99 : SRV6_AD_LOCALSID_N_NEXT,
100 : } srv6_ad_localsid_next_t;
101 :
102 : typedef enum
103 : {
104 : SRV6_AD_REWRITE_NEXT_ERROR,
105 : SRV6_AD_REWRITE_NEXT_LOOKUP,
106 : SRV6_AD_REWRITE_N_NEXT,
107 : } srv6_ad_rewrite_next_t;
108 :
109 :
110 : /******************************* Local SID node *******************************/
111 :
112 : /**
113 : * @brief Function doing SRH processing for AD behavior
114 : */
115 : static_always_inline void
116 9 : end_ad_processing (vlib_buffer_t * b0,
117 : ip6_header_t * ip0,
118 : ip6_sr_header_t * sr0,
119 : ip6_sr_localsid_t * ls0, u32 * next0)
120 : {
121 : ip6_address_t *new_dst0;
122 : u16 total_size;
123 : ip6_ext_header_t *next_ext_header;
124 : u8 next_hdr;
125 : srv6_ad_localsid_t *ls0_mem;
126 :
127 9 : if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
128 : sr0->type != ROUTING_HEADER_TYPE_SR))
129 : {
130 0 : return;
131 : }
132 :
133 9 : if (PREDICT_FALSE (sr0->segments_left == 0))
134 : {
135 0 : return;
136 : }
137 :
138 : /* Decrement Segments Left and update Destination Address */
139 9 : sr0->segments_left -= 1;
140 9 : new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
141 9 : ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
142 9 : ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
143 :
144 : /* Compute the total size of the IPv6 header and extensions */
145 9 : total_size = sizeof (ip6_header_t);
146 9 : next_ext_header = (ip6_ext_header_t *) (ip0 + 1);
147 9 : next_hdr = ip0->protocol;
148 :
149 18 : while (ip6_ext_hdr (next_hdr))
150 : {
151 9 : total_size += ip6_ext_header_len (next_ext_header);
152 9 : next_hdr = next_ext_header->next_hdr;
153 9 : next_ext_header = ip6_ext_next_header (next_ext_header);
154 : }
155 :
156 : /* Make sure next header is valid */
157 9 : if (PREDICT_FALSE (next_hdr != IP_PROTOCOL_IPV6 &&
158 : next_hdr != IP_PROTOCOL_IP_IN_IP &&
159 : next_hdr != IP_PROTOCOL_IP6_ETHERNET))
160 : {
161 0 : return;
162 : }
163 :
164 : /* Retrieve SID memory */
165 9 : ls0_mem = ls0->plugin_mem;
166 :
167 : /* Cache IP header and extensions */
168 9 : if (PREDICT_FALSE (total_size > ls0_mem->rw_len))
169 : {
170 3 : vec_validate (ls0_mem->rewrite, total_size - 1);
171 : }
172 9 : clib_memcpy_fast (ls0_mem->rewrite, ip0, total_size);
173 9 : ls0_mem->rw_len = total_size;
174 :
175 : /* Remove IP header and extensions */
176 9 : vlib_buffer_advance (b0, total_size);
177 :
178 9 : if (next_hdr == IP_PROTOCOL_IP6_ETHERNET)
179 : {
180 : /* Set output interface */
181 3 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0_mem->sw_if_index_out;
182 :
183 : /* Set next node to interface-output */
184 3 : *next0 = SRV6_AD_LOCALSID_NEXT_INTERFACE;
185 : }
186 : else
187 : {
188 : /* Set Xconnect adjacency to VNF */
189 6 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
190 :
191 : /* Set next node to ip-rewrite */
192 6 : *next0 = (next_hdr == IP_PROTOCOL_IPV6) ?
193 6 : SRV6_AD_LOCALSID_NEXT_REWRITE6 : SRV6_AD_LOCALSID_NEXT_REWRITE4;
194 : }
195 : }
196 :
197 : /**
198 : * @brief SRv6 AD Localsid graph node
199 : */
200 : static uword
201 3 : srv6_ad_localsid_fn (vlib_main_t * vm,
202 : vlib_node_runtime_t * node, vlib_frame_t * frame)
203 : {
204 3 : ip6_sr_main_t *sm = &sr_main;
205 : u32 n_left_from, next_index, *from, *to_next;
206 :
207 3 : from = vlib_frame_vector_args (frame);
208 3 : n_left_from = frame->n_vectors;
209 3 : next_index = node->cached_next_index;
210 :
211 6 : while (n_left_from > 0)
212 : {
213 : u32 n_left_to_next;
214 :
215 3 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
216 :
217 : /* TODO: Dual/quad loop */
218 :
219 12 : while (n_left_from > 0 && n_left_to_next > 0)
220 : {
221 : u32 bi0;
222 : vlib_buffer_t *b0;
223 9 : ip6_header_t *ip0 = 0;
224 : ip6_sr_header_t *sr0;
225 : ip6_sr_localsid_t *ls0;
226 9 : u32 next0 = SRV6_AD_LOCALSID_NEXT_ERROR;
227 :
228 9 : bi0 = from[0];
229 9 : to_next[0] = bi0;
230 9 : from += 1;
231 9 : to_next += 1;
232 9 : n_left_from -= 1;
233 9 : n_left_to_next -= 1;
234 :
235 9 : b0 = vlib_get_buffer (vm, bi0);
236 9 : ip0 = vlib_buffer_get_current (b0);
237 9 : sr0 = (ip6_sr_header_t *) (ip0 + 1);
238 :
239 : /* Lookup the SR End behavior based on IP DA (adj) */
240 9 : ls0 = pool_elt_at_index (sm->localsids,
241 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
242 :
243 : /* SRH processing */
244 9 : end_ad_processing (b0, ip0, sr0, ls0, &next0);
245 :
246 9 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
247 : {
248 : srv6_ad_localsid_trace_t *tr =
249 9 : vlib_add_trace (vm, node, b0, sizeof *tr);
250 9 : tr->localsid_index = ls0 - sm->localsids;
251 : }
252 :
253 : /* This increments the SRv6 per LocalSID counters. */
254 18 : vlib_increment_combined_counter (((next0 ==
255 : SRV6_AD_LOCALSID_NEXT_ERROR) ?
256 : &(sm->sr_ls_invalid_counters) :
257 : &(sm->sr_ls_valid_counters)),
258 : vm->thread_index,
259 9 : ls0 - sm->localsids, 1,
260 : vlib_buffer_length_in_chain (vm,
261 : b0));
262 :
263 9 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
264 : n_left_to_next, bi0, next0);
265 :
266 : }
267 :
268 3 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
269 : }
270 :
271 3 : return frame->n_vectors;
272 : }
273 :
274 : /* *INDENT-OFF* */
275 39199 : VLIB_REGISTER_NODE (srv6_ad_localsid_node) = {
276 : .function = srv6_ad_localsid_fn,
277 : .name = "srv6-ad-localsid",
278 : .vector_size = sizeof (u32),
279 : .format_trace = format_srv6_ad_localsid_trace,
280 : .type = VLIB_NODE_TYPE_INTERNAL,
281 : .n_next_nodes = SRV6_AD_LOCALSID_N_NEXT,
282 : .next_nodes = {
283 : [SRV6_AD_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
284 : [SRV6_AD_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
285 : [SRV6_AD_LOCALSID_NEXT_INTERFACE] = "interface-output",
286 : [SRV6_AD_LOCALSID_NEXT_ERROR] = "error-drop",
287 : },
288 : };
289 : /* *INDENT-ON* */
290 :
291 :
292 : /******************************* Rewriting node *******************************/
293 :
294 : /**
295 : * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
296 : */
297 : static uword
298 1 : srv6_ad2_rewrite_fn (vlib_main_t * vm,
299 : vlib_node_runtime_t * node, vlib_frame_t * frame)
300 : {
301 1 : ip6_sr_main_t *srm = &sr_main;
302 1 : srv6_ad_main_t *sm = &srv6_ad_main;
303 : u32 n_left_from, next_index, *from, *to_next;
304 1 : u32 cnt_packets = 0;
305 :
306 1 : from = vlib_frame_vector_args (frame);
307 1 : n_left_from = frame->n_vectors;
308 1 : next_index = node->cached_next_index;
309 :
310 2 : while (n_left_from > 0)
311 : {
312 : u32 n_left_to_next;
313 :
314 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
315 :
316 : /* TODO: Dual/quad loop */
317 :
318 4 : while (n_left_from > 0 && n_left_to_next > 0)
319 : {
320 : u32 bi0;
321 : vlib_buffer_t *b0;
322 : ethernet_header_t *en0;
323 3 : ip6_header_t *ip0 = 0;
324 : ip6_sr_localsid_t *ls0;
325 : srv6_ad_localsid_t *ls0_mem;
326 3 : u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
327 :
328 3 : bi0 = from[0];
329 3 : to_next[0] = bi0;
330 3 : from += 1;
331 3 : to_next += 1;
332 3 : n_left_from -= 1;
333 3 : n_left_to_next -= 1;
334 :
335 3 : b0 = vlib_get_buffer (vm, bi0);
336 3 : en0 = vlib_buffer_get_current (b0);
337 3 : ls0 = pool_elt_at_index (srm->localsids,
338 : sm->sw_iface_localsid2[vnet_buffer
339 : (b0)->sw_if_index
340 : [VLIB_RX]]);
341 3 : ls0_mem = ls0->plugin_mem;
342 :
343 3 : if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
344 : {
345 0 : next0 = SRV6_AD_REWRITE_NEXT_ERROR;
346 0 : b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
347 : }
348 : else
349 : {
350 3 : ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
351 : (ls0_mem->rw_len + b0->current_data));
352 :
353 3 : clib_memcpy_fast (((u8 *) en0) - ls0_mem->rw_len,
354 3 : ls0_mem->rewrite, ls0_mem->rw_len);
355 3 : vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
356 :
357 3 : ip0 = vlib_buffer_get_current (b0);
358 :
359 3 : ip0->payload_length =
360 3 : clib_host_to_net_u16 (b0->current_length -
361 : sizeof (ip6_header_t));
362 : }
363 :
364 3 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
365 3 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
366 : {
367 : srv6_ad_rewrite_trace_t *tr =
368 3 : vlib_add_trace (vm, node, b0, sizeof *tr);
369 3 : tr->error = 0;
370 :
371 3 : if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
372 : {
373 0 : tr->error = 1;
374 : }
375 : else
376 : {
377 3 : clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
378 : sizeof tr->src.as_u8);
379 3 : clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
380 : sizeof tr->dst.as_u8);
381 : }
382 : }
383 :
384 : /* Increment per-SID AD rewrite counters */
385 3 : vlib_increment_combined_counter (((next0 ==
386 : SRV6_AD_LOCALSID_NEXT_ERROR) ?
387 : &(sm->invalid_counters) :
388 : &(sm->valid_counters)),
389 : vm->thread_index, ls0_mem->index,
390 : 1, vlib_buffer_length_in_chain (vm,
391 : b0));
392 :
393 3 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
394 : n_left_to_next, bi0, next0);
395 :
396 3 : cnt_packets++;
397 : }
398 :
399 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
400 : }
401 :
402 : /* Update counters */
403 1 : vlib_node_increment_counter (vm, srv6_ad4_rewrite_node.index,
404 : SRV6_AD_REWRITE_COUNTER_PROCESSED,
405 : cnt_packets);
406 :
407 1 : return frame->n_vectors;
408 : }
409 :
410 : /* *INDENT-OFF* */
411 39199 : VLIB_REGISTER_NODE (srv6_ad2_rewrite_node) = {
412 : .function = srv6_ad2_rewrite_fn,
413 : .name = "srv6-ad2-rewrite",
414 : .vector_size = sizeof (u32),
415 : .format_trace = format_srv6_ad_rewrite_trace,
416 : .type = VLIB_NODE_TYPE_INTERNAL,
417 : .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
418 : .error_strings = srv6_ad_rewrite_counter_strings,
419 : .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
420 : .next_nodes = {
421 : [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
422 : [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
423 : },
424 : };
425 : /* *INDENT-ON* */
426 :
427 :
428 : /**
429 : * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
430 : */
431 : static uword
432 1 : srv6_ad4_rewrite_fn (vlib_main_t * vm,
433 : vlib_node_runtime_t * node, vlib_frame_t * frame)
434 : {
435 1 : ip6_sr_main_t *srm = &sr_main;
436 1 : srv6_ad_main_t *sm = &srv6_ad_main;
437 : u32 n_left_from, next_index, *from, *to_next;
438 1 : u32 cnt_packets = 0;
439 :
440 1 : from = vlib_frame_vector_args (frame);
441 1 : n_left_from = frame->n_vectors;
442 1 : next_index = node->cached_next_index;
443 :
444 2 : while (n_left_from > 0)
445 : {
446 : u32 n_left_to_next;
447 :
448 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
449 :
450 : /* TODO: Dual/quad loop */
451 :
452 4 : while (n_left_from > 0 && n_left_to_next > 0)
453 : {
454 : u32 bi0;
455 : vlib_buffer_t *b0;
456 3 : ip4_header_t *ip0_encap = 0;
457 3 : ip6_header_t *ip0 = 0;
458 : ip6_sr_localsid_t *ls0;
459 : srv6_ad_localsid_t *ls0_mem;
460 3 : u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
461 3 : u16 new_l0 = 0;
462 :
463 3 : bi0 = from[0];
464 3 : to_next[0] = bi0;
465 3 : from += 1;
466 3 : to_next += 1;
467 3 : n_left_from -= 1;
468 3 : n_left_to_next -= 1;
469 :
470 3 : b0 = vlib_get_buffer (vm, bi0);
471 3 : ip0_encap = vlib_buffer_get_current (b0);
472 3 : ls0 = pool_elt_at_index (srm->localsids,
473 : sm->sw_iface_localsid4[vnet_buffer
474 : (b0)->sw_if_index
475 : [VLIB_RX]]);
476 3 : ls0_mem = ls0->plugin_mem;
477 :
478 3 : if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
479 : {
480 0 : next0 = SRV6_AD_REWRITE_NEXT_ERROR;
481 0 : b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
482 : }
483 : else
484 : {
485 3 : ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
486 : (ls0_mem->rw_len + b0->current_data));
487 :
488 3 : clib_memcpy_fast (((u8 *) ip0_encap) - ls0_mem->rw_len,
489 3 : ls0_mem->rewrite, ls0_mem->rw_len);
490 3 : vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
491 :
492 3 : ip0 = vlib_buffer_get_current (b0);
493 :
494 : /* Update inner IPv4 TTL and checksum */
495 : u32 checksum0;
496 3 : ip0_encap->ttl -= 1;
497 3 : checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
498 3 : checksum0 += checksum0 >= 0xffff;
499 3 : ip0_encap->checksum = checksum0;
500 :
501 : /* Update outer IPv6 length (in case it has changed) */
502 6 : new_l0 = ls0_mem->rw_len - sizeof (ip6_header_t) +
503 3 : clib_net_to_host_u16 (ip0_encap->length);
504 3 : ip0->payload_length = clib_host_to_net_u16 (new_l0);
505 : }
506 :
507 3 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
508 3 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
509 : {
510 : srv6_ad_rewrite_trace_t *tr =
511 3 : vlib_add_trace (vm, node, b0, sizeof *tr);
512 3 : tr->error = 0;
513 :
514 3 : if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
515 : {
516 0 : tr->error = 1;
517 : }
518 : else
519 : {
520 3 : clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
521 : sizeof tr->src.as_u8);
522 3 : clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
523 : sizeof tr->dst.as_u8);
524 : }
525 : }
526 :
527 : /* Increment per-SID AD rewrite counters */
528 3 : vlib_increment_combined_counter (((next0 ==
529 : SRV6_AD_LOCALSID_NEXT_ERROR) ?
530 : &(sm->invalid_counters) :
531 : &(sm->valid_counters)),
532 : vm->thread_index, ls0_mem->index,
533 : 1, vlib_buffer_length_in_chain (vm,
534 : b0));
535 :
536 3 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
537 : n_left_to_next, bi0, next0);
538 :
539 3 : cnt_packets++;
540 : }
541 :
542 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
543 : }
544 :
545 : /* Update counters */
546 1 : vlib_node_increment_counter (vm, srv6_ad4_rewrite_node.index,
547 : SRV6_AD_REWRITE_COUNTER_PROCESSED,
548 : cnt_packets);
549 :
550 1 : return frame->n_vectors;
551 : }
552 :
553 : /* *INDENT-OFF* */
554 39199 : VLIB_REGISTER_NODE (srv6_ad4_rewrite_node) = {
555 : .function = srv6_ad4_rewrite_fn,
556 : .name = "srv6-ad4-rewrite",
557 : .vector_size = sizeof (u32),
558 : .format_trace = format_srv6_ad_rewrite_trace,
559 : .type = VLIB_NODE_TYPE_INTERNAL,
560 : .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
561 : .error_strings = srv6_ad_rewrite_counter_strings,
562 : .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
563 : .next_nodes = {
564 : [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
565 : [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
566 : },
567 : };
568 : /* *INDENT-ON* */
569 :
570 :
571 : /**
572 : * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
573 : */
574 : static uword
575 1 : srv6_ad6_rewrite_fn (vlib_main_t * vm,
576 : vlib_node_runtime_t * node, vlib_frame_t * frame)
577 : {
578 1 : ip6_sr_main_t *srm = &sr_main;
579 1 : srv6_ad_main_t *sm = &srv6_ad_main;
580 : u32 n_left_from, next_index, *from, *to_next;
581 1 : u32 cnt_packets = 0;
582 :
583 1 : from = vlib_frame_vector_args (frame);
584 1 : n_left_from = frame->n_vectors;
585 1 : next_index = node->cached_next_index;
586 :
587 2 : while (n_left_from > 0)
588 : {
589 : u32 n_left_to_next;
590 :
591 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
592 :
593 : /* TODO: Dual/quad loop */
594 :
595 4 : while (n_left_from > 0 && n_left_to_next > 0)
596 : {
597 : u32 bi0;
598 : vlib_buffer_t *b0;
599 3 : ip6_header_t *ip0 = 0, *ip0_encap = 0;
600 : ip6_sr_localsid_t *ls0;
601 : srv6_ad_localsid_t *ls0_mem;
602 3 : u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
603 3 : u16 new_l0 = 0;
604 :
605 3 : bi0 = from[0];
606 3 : to_next[0] = bi0;
607 3 : from += 1;
608 3 : to_next += 1;
609 3 : n_left_from -= 1;
610 3 : n_left_to_next -= 1;
611 :
612 3 : b0 = vlib_get_buffer (vm, bi0);
613 3 : ip0_encap = vlib_buffer_get_current (b0);
614 3 : ls0 = pool_elt_at_index (srm->localsids,
615 : sm->sw_iface_localsid6[vnet_buffer
616 : (b0)->sw_if_index
617 : [VLIB_RX]]);
618 3 : ls0_mem = ls0->plugin_mem;
619 :
620 3 : if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
621 : {
622 0 : next0 = SRV6_AD_REWRITE_NEXT_ERROR;
623 0 : b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
624 : }
625 : else
626 : {
627 3 : ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
628 : (ls0_mem->rw_len + b0->current_data));
629 :
630 3 : clib_memcpy_fast (((u8 *) ip0_encap) - ls0_mem->rw_len,
631 3 : ls0_mem->rewrite, ls0_mem->rw_len);
632 3 : vlib_buffer_advance (b0, -(word) ls0_mem->rw_len);
633 :
634 3 : ip0 = vlib_buffer_get_current (b0);
635 :
636 : /* Update inner IPv6 hop limit */
637 3 : ip0_encap->hop_limit -= 1;
638 :
639 : /* Update outer IPv6 length (in case it has changed) */
640 6 : new_l0 = ls0_mem->rw_len +
641 3 : clib_net_to_host_u16 (ip0_encap->payload_length);
642 3 : ip0->payload_length = clib_host_to_net_u16 (new_l0);
643 : }
644 :
645 3 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
646 3 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
647 : {
648 : srv6_ad_rewrite_trace_t *tr =
649 3 : vlib_add_trace (vm, node, b0, sizeof *tr);
650 3 : tr->error = 0;
651 :
652 3 : if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
653 : {
654 0 : tr->error = 1;
655 : }
656 : else
657 : {
658 3 : clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
659 : sizeof tr->src.as_u8);
660 3 : clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
661 : sizeof tr->dst.as_u8);
662 : }
663 : }
664 :
665 : /* Increment per-SID AD rewrite counters */
666 3 : vlib_increment_combined_counter (((next0 ==
667 : SRV6_AD_LOCALSID_NEXT_ERROR) ?
668 : &(sm->invalid_counters) :
669 : &(sm->valid_counters)),
670 : vm->thread_index, ls0_mem->index,
671 : 1, vlib_buffer_length_in_chain (vm,
672 : b0));
673 :
674 3 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
675 : n_left_to_next, bi0, next0);
676 :
677 3 : cnt_packets++;
678 : }
679 :
680 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
681 : }
682 :
683 : /* Update counters */
684 1 : vlib_node_increment_counter (vm, srv6_ad6_rewrite_node.index,
685 : SRV6_AD_REWRITE_COUNTER_PROCESSED,
686 : cnt_packets);
687 :
688 1 : return frame->n_vectors;
689 : }
690 :
691 : /* *INDENT-OFF* */
692 39199 : VLIB_REGISTER_NODE (srv6_ad6_rewrite_node) = {
693 : .function = srv6_ad6_rewrite_fn,
694 : .name = "srv6-ad6-rewrite",
695 : .vector_size = sizeof (u32),
696 : .format_trace = format_srv6_ad_rewrite_trace,
697 : .type = VLIB_NODE_TYPE_INTERNAL,
698 : .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
699 : .error_strings = srv6_ad_rewrite_counter_strings,
700 : .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
701 : .next_nodes = {
702 : [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
703 : [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
704 : },
705 : };
706 : /* *INDENT-ON* */
707 :
708 : /*
709 : * fd.io coding-style-patch-verification: ON
710 : *
711 : * Local Variables:
712 : * eval: (c-set-style "gnu")
713 : * End:
714 : */
|