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