srv6-ad: fixing coverity issues
[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_N_NEXT,
96 } srv6_ad_localsid_next_t;
97
98 typedef enum
99 {
100   SRV6_AD_REWRITE_NEXT_ERROR,
101   SRV6_AD_REWRITE_NEXT_LOOKUP,
102   SRV6_AD_REWRITE_N_NEXT,
103 } srv6_ad_rewrite_next_t;
104
105
106 /******************************* Local SID node *******************************/
107
108 /**
109  * @brief Function doing SRH processing for AD behavior
110  */
111 static_always_inline void
112 end_ad_processing (vlib_buffer_t * b0,
113                    ip6_header_t * ip0,
114                    ip6_sr_header_t * sr0,
115                    ip6_sr_localsid_t * ls0, u32 * next0)
116 {
117   ip6_address_t *new_dst0;
118   u16 total_size;
119   ip6_ext_header_t *next_ext_header;
120   u8 next_hdr;
121   srv6_ad_localsid_t *ls0_mem;
122
123   if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
124                      sr0->type != ROUTING_HEADER_TYPE_SR))
125     {
126       return;
127     }
128
129   if (PREDICT_FALSE (sr0->segments_left == 0))
130     {
131       return;
132     }
133
134   /* Decrement Segments Left and update Destination Address */
135   sr0->segments_left -= 1;
136   new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
137   ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
138   ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
139
140   /* Compute the total size of the IPv6 header and extensions */
141   total_size = sizeof (ip6_header_t);
142   next_ext_header = (ip6_ext_header_t *) (ip0 + 1);
143   next_hdr = ip0->protocol;
144
145   while (ip6_ext_hdr (next_hdr))
146     {
147       total_size += ip6_ext_header_len (next_ext_header);
148       next_hdr = next_ext_header->next_hdr;
149       next_ext_header = ip6_ext_next_header (next_ext_header);
150     }
151
152   /* Make sure next header is IP */
153   if (PREDICT_FALSE
154       (next_hdr != IP_PROTOCOL_IPV6 && next_hdr != IP_PROTOCOL_IP_IN_IP))
155     {
156       return;
157     }
158
159   /* Retrieve SID memory */
160   ls0_mem = ls0->plugin_mem;
161
162   /* Cache IP header and extensions */
163   vec_validate (ls0_mem->rewrite, total_size - 1);
164   clib_memcpy (ls0_mem->rewrite, ip0, total_size);
165
166   /* Remove IP header and extensions */
167   vlib_buffer_advance (b0, total_size);
168
169   /* Set Xconnect adjacency to VNF */
170   vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0_mem->nh_adj;
171
172   if (ls0_mem->ip_version == DA_IP4)
173     *next0 = SRV6_AD_LOCALSID_NEXT_REWRITE4;
174   else if (ls0_mem->ip_version == DA_IP6)
175     *next0 = SRV6_AD_LOCALSID_NEXT_REWRITE6;
176 }
177
178 /**
179  * @brief SRv6 AD Localsid graph node
180  */
181 static uword
182 srv6_ad_localsid_fn (vlib_main_t * vm,
183                      vlib_node_runtime_t * node, vlib_frame_t * frame)
184 {
185   ip6_sr_main_t *sm = &sr_main;
186   u32 n_left_from, next_index, *from, *to_next;
187   u32 cnt_packets = 0;
188
189   from = vlib_frame_vector_args (frame);
190   n_left_from = frame->n_vectors;
191   next_index = node->cached_next_index;
192
193   u32 thread_index = vlib_get_thread_index ();
194
195   while (n_left_from > 0)
196     {
197       u32 n_left_to_next;
198
199       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
200
201       /* TODO: Dual/quad loop */
202
203       while (n_left_from > 0 && n_left_to_next > 0)
204         {
205           u32 bi0;
206           vlib_buffer_t *b0;
207           ip6_header_t *ip0 = 0;
208           ip6_sr_header_t *sr0;
209           ip6_sr_localsid_t *ls0;
210           u32 next0 = SRV6_AD_LOCALSID_NEXT_ERROR;
211
212           bi0 = from[0];
213           to_next[0] = bi0;
214           from += 1;
215           to_next += 1;
216           n_left_from -= 1;
217           n_left_to_next -= 1;
218
219           b0 = vlib_get_buffer (vm, bi0);
220           ip0 = vlib_buffer_get_current (b0);
221           sr0 = (ip6_sr_header_t *) (ip0 + 1);
222
223           /* Lookup the SR End behavior based on IP DA (adj) */
224           ls0 = pool_elt_at_index (sm->localsids,
225                                    vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
226
227           /* SRH processing */
228           end_ad_processing (b0, ip0, sr0, ls0, &next0);
229
230           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
231             {
232               srv6_ad_localsid_trace_t *tr =
233                 vlib_add_trace (vm, node, b0, sizeof *tr);
234               tr->localsid_index = ls0 - sm->localsids;
235             }
236
237           /* This increments the SRv6 per LocalSID counters. */
238           vlib_increment_combined_counter (((next0 ==
239                                              SRV6_AD_LOCALSID_NEXT_ERROR) ?
240                                             &(sm->sr_ls_invalid_counters) :
241                                             &(sm->sr_ls_valid_counters)),
242                                            thread_index, ls0 - sm->localsids,
243                                            1, vlib_buffer_length_in_chain (vm,
244                                                                            b0));
245
246           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
247                                            n_left_to_next, bi0, next0);
248
249           cnt_packets++;
250         }
251
252       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
253     }
254
255   return frame->n_vectors;
256 }
257
258 /* *INDENT-OFF* */
259 VLIB_REGISTER_NODE (srv6_ad_localsid_node) = {
260   .function = srv6_ad_localsid_fn,
261   .name = "srv6-ad-localsid",
262   .vector_size = sizeof (u32),
263   .format_trace = format_srv6_ad_localsid_trace,
264   .type = VLIB_NODE_TYPE_INTERNAL,
265   .n_next_nodes = SRV6_AD_LOCALSID_N_NEXT,
266   .next_nodes = {
267     [SRV6_AD_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
268     [SRV6_AD_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
269     [SRV6_AD_LOCALSID_NEXT_ERROR] = "error-drop",
270   },
271 };
272 /* *INDENT-ON* */
273
274
275 /******************************* Rewriting node *******************************/
276
277 /**
278  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
279  */
280 static uword
281 srv6_ad4_rewrite_fn (vlib_main_t * vm,
282                      vlib_node_runtime_t * node, vlib_frame_t * frame)
283 {
284   ip6_sr_main_t *srm = &sr_main;
285   srv6_ad_main_t *sm = &srv6_ad_main;
286   u32 n_left_from, next_index, *from, *to_next;
287   u32 cnt_packets = 0;
288
289   from = vlib_frame_vector_args (frame);
290   n_left_from = frame->n_vectors;
291   next_index = node->cached_next_index;
292
293   while (n_left_from > 0)
294     {
295       u32 n_left_to_next;
296
297       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
298
299       /* TODO: Dual/quad loop */
300
301       while (n_left_from > 0 && n_left_to_next > 0)
302         {
303           u32 bi0;
304           vlib_buffer_t *b0;
305           ip4_header_t *ip0_encap = 0;
306           ip6_header_t *ip0 = 0;
307           ip6_sr_localsid_t *ls0;
308           srv6_ad_localsid_t *ls0_mem;
309           u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
310           u16 new_l0 = 0;
311
312           bi0 = from[0];
313           to_next[0] = bi0;
314           from += 1;
315           to_next += 1;
316           n_left_from -= 1;
317           n_left_to_next -= 1;
318
319           b0 = vlib_get_buffer (vm, bi0);
320           ip0_encap = vlib_buffer_get_current (b0);
321           ls0 = pool_elt_at_index (srm->localsids,
322                                    sm->sw_iface_localsid4[vnet_buffer
323                                                           (b0)->sw_if_index
324                                                           [VLIB_RX]]);
325           ls0_mem = ls0->plugin_mem;
326
327           if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
328             {
329               next0 = SRV6_AD_REWRITE_NEXT_ERROR;
330               b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
331             }
332           else
333             {
334               ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
335                       (vec_len (ls0_mem->rewrite) + b0->current_data));
336
337               clib_memcpy (((u8 *) ip0_encap) - vec_len (ls0_mem->rewrite),
338                            ls0_mem->rewrite, vec_len (ls0_mem->rewrite));
339               vlib_buffer_advance (b0, -(word) vec_len (ls0_mem->rewrite));
340
341               ip0 = vlib_buffer_get_current (b0);
342
343               /* Update inner IPv4 TTL and checksum */
344               u32 checksum0;
345               ip0_encap->ttl -= 1;
346               checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
347               checksum0 += checksum0 >= 0xffff;
348               ip0_encap->checksum = checksum0;
349
350               /* Update outer IPv6 length (in case it has changed) */
351               new_l0 = vec_len (ls0_mem->rewrite) - sizeof (ip6_header_t) +
352                 clib_net_to_host_u16 (ip0_encap->length);
353               ip0->payload_length = clib_host_to_net_u16 (new_l0);
354             }
355
356           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
357               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
358             {
359               srv6_ad_rewrite_trace_t *tr =
360                 vlib_add_trace (vm, node, b0, sizeof *tr);
361               tr->error = 0;
362
363               if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
364                 {
365                   tr->error = 1;
366                 }
367               else
368                 {
369                   clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
370                                sizeof tr->src.as_u8);
371                   clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
372                                sizeof tr->dst.as_u8);
373                 }
374             }
375
376           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
377                                            n_left_to_next, bi0, next0);
378
379           cnt_packets++;
380         }
381
382       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
383     }
384
385   /* Update counters */
386   vlib_node_increment_counter (vm, srv6_ad4_rewrite_node.index,
387                                SRV6_AD_REWRITE_COUNTER_PROCESSED,
388                                cnt_packets);
389
390   return frame->n_vectors;
391 }
392
393 /* *INDENT-OFF* */
394 VLIB_REGISTER_NODE (srv6_ad4_rewrite_node) = {
395   .function = srv6_ad4_rewrite_fn,
396   .name = "srv6-ad4-rewrite",
397   .vector_size = sizeof (u32),
398   .format_trace = format_srv6_ad_rewrite_trace,
399   .type = VLIB_NODE_TYPE_INTERNAL,
400   .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
401   .error_strings = srv6_ad_rewrite_counter_strings,
402   .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
403   .next_nodes = {
404       [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
405       [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
406   },
407 };
408 /* *INDENT-ON* */
409
410
411 /**
412  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
413  */
414 static uword
415 srv6_ad6_rewrite_fn (vlib_main_t * vm,
416                      vlib_node_runtime_t * node, vlib_frame_t * frame)
417 {
418   ip6_sr_main_t *srm = &sr_main;
419   srv6_ad_main_t *sm = &srv6_ad_main;
420   u32 n_left_from, next_index, *from, *to_next;
421   u32 cnt_packets = 0;
422
423   from = vlib_frame_vector_args (frame);
424   n_left_from = frame->n_vectors;
425   next_index = node->cached_next_index;
426
427   while (n_left_from > 0)
428     {
429       u32 n_left_to_next;
430
431       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
432
433       /* TODO: Dual/quad loop */
434
435       while (n_left_from > 0 && n_left_to_next > 0)
436         {
437           u32 bi0;
438           vlib_buffer_t *b0;
439           ip6_header_t *ip0 = 0, *ip0_encap = 0;
440           ip6_sr_localsid_t *ls0;
441           srv6_ad_localsid_t *ls0_mem;
442           u32 next0 = SRV6_AD_REWRITE_NEXT_LOOKUP;
443           u16 new_l0 = 0;
444
445           bi0 = from[0];
446           to_next[0] = bi0;
447           from += 1;
448           to_next += 1;
449           n_left_from -= 1;
450           n_left_to_next -= 1;
451
452           b0 = vlib_get_buffer (vm, bi0);
453           ip0_encap = vlib_buffer_get_current (b0);
454           ls0 = pool_elt_at_index (srm->localsids,
455                                    sm->sw_iface_localsid6[vnet_buffer
456                                                           (b0)->sw_if_index
457                                                           [VLIB_RX]]);
458           ls0_mem = ls0->plugin_mem;
459
460           if (PREDICT_FALSE (ls0_mem == NULL || ls0_mem->rewrite == NULL))
461             {
462               next0 = SRV6_AD_REWRITE_NEXT_ERROR;
463               b0->error = node->errors[SRV6_AD_REWRITE_COUNTER_NO_RW];
464             }
465           else
466             {
467               ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
468                       (vec_len (ls0_mem->rewrite) + b0->current_data));
469
470               clib_memcpy (((u8 *) ip0_encap) - vec_len (ls0_mem->rewrite),
471                            ls0_mem->rewrite, vec_len (ls0_mem->rewrite));
472               vlib_buffer_advance (b0, -(word) vec_len (ls0_mem->rewrite));
473
474               ip0 = vlib_buffer_get_current (b0);
475
476               /* Update inner IPv6 hop limit */
477               ip0_encap->hop_limit -= 1;
478
479               /* Update outer IPv6 length (in case it has changed) */
480               new_l0 = vec_len (ls0_mem->rewrite) +
481                 clib_net_to_host_u16 (ip0_encap->payload_length);
482               ip0->payload_length = clib_host_to_net_u16 (new_l0);
483             }
484
485           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
486               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
487             {
488               srv6_ad_rewrite_trace_t *tr =
489                 vlib_add_trace (vm, node, b0, sizeof *tr);
490               tr->error = 0;
491
492               if (next0 == SRV6_AD_REWRITE_NEXT_ERROR)
493                 {
494                   tr->error = 1;
495                 }
496               else
497                 {
498                   clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
499                                sizeof tr->src.as_u8);
500                   clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
501                                sizeof tr->dst.as_u8);
502                 }
503             }
504
505           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
506                                            n_left_to_next, bi0, next0);
507
508           cnt_packets++;
509         }
510
511       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
512     }
513
514   /* Update counters */
515   vlib_node_increment_counter (vm, srv6_ad6_rewrite_node.index,
516                                SRV6_AD_REWRITE_COUNTER_PROCESSED,
517                                cnt_packets);
518
519   return frame->n_vectors;
520 }
521
522 /* *INDENT-OFF* */
523 VLIB_REGISTER_NODE (srv6_ad6_rewrite_node) = {
524   .function = srv6_ad6_rewrite_fn,
525   .name = "srv6-ad6-rewrite",
526   .vector_size = sizeof (u32),
527   .format_trace = format_srv6_ad_rewrite_trace,
528   .type = VLIB_NODE_TYPE_INTERNAL,
529   .n_errors = SRV6_AD_REWRITE_N_COUNTERS,
530   .error_strings = srv6_ad_rewrite_counter_strings,
531   .n_next_nodes = SRV6_AD_REWRITE_N_NEXT,
532   .next_nodes = {
533       [SRV6_AD_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
534       [SRV6_AD_REWRITE_NEXT_ERROR] = "error-drop",
535   },
536 };
537 /* *INDENT-ON* */
538
539 /*
540 * fd.io coding-style-patch-verification: ON
541 *
542 * Local Variables:
543 * eval: (c-set-style "gnu")
544 * End:
545 */