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