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