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