Remove c-11 memcpy checks from perf-critical code
[vpp.git] / src / plugins / srv6-am / 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-am/am.h>
19
20
21 /******************************* Packet tracing *******************************/
22
23 typedef struct
24 {
25   u32 localsid_index;
26 } srv6_am_localsid_trace_t;
27
28 typedef struct
29 {
30   ip6_address_t src, dst;
31 } srv6_am_rewrite_trace_t;
32
33 static u8 *
34 format_srv6_am_localsid_trace (u8 * s, va_list * args)
35 {
36   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38   srv6_am_localsid_trace_t *t = va_arg (*args, srv6_am_localsid_trace_t *);
39
40   return format (s, "SRv6-AM-localsid: localsid_index %d", t->localsid_index);
41 }
42
43 static u8 *
44 format_srv6_am_rewrite_trace (u8 * s, va_list * args)
45 {
46   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48   srv6_am_rewrite_trace_t *t = va_arg (*args, srv6_am_rewrite_trace_t *);
49
50   return format (s, "SRv6-AM-rewrite: src %U dst %U",
51                  format_ip6_address, &t->src, format_ip6_address, &t->dst);
52 }
53
54
55 /***************************** Node registration ******************************/
56
57 vlib_node_registration_t srv6_am_rewrite_node;
58
59
60 /****************************** Packet counters *******************************/
61
62 #define foreach_srv6_am_rewrite_counter \
63 _(PROCESSED, "srv6-am rewritten packets") \
64 _(NO_SRH, "(Error) No SRH.")
65
66 typedef enum
67 {
68 #define _(sym,str) SRV6_AM_REWRITE_COUNTER_##sym,
69   foreach_srv6_am_rewrite_counter
70 #undef _
71     SRV6_AM_REWRITE_N_COUNTERS,
72 } srv6_am_rewrite_counters;
73
74 static char *srv6_am_rewrite_counter_strings[] = {
75 #define _(sym,string) string,
76   foreach_srv6_am_rewrite_counter
77 #undef _
78 };
79
80
81 /********************************* Next nodes *********************************/
82
83 typedef enum
84 {
85   SRV6_AM_LOCALSID_NEXT_ERROR,
86   SRV6_AM_LOCALSID_NEXT_REWRITE,
87   SRV6_AM_LOCALSID_N_NEXT,
88 } srv6_am_localsid_next_t;
89
90 typedef enum
91 {
92   SRV6_AM_REWRITE_NEXT_ERROR,
93   SRV6_AM_REWRITE_NEXT_LOOKUP,
94   SRV6_AM_REWRITE_N_NEXT,
95 } srv6_am_rewrite_next_t;
96
97
98 /******************************* Local SID node *******************************/
99
100 /**
101  * @brief SRv6 masquerading.
102  */
103 static_always_inline void
104 end_am_processing (vlib_buffer_t * b0,
105                    ip6_header_t * ip0,
106                    ip6_sr_header_t * sr0,
107                    ip6_sr_localsid_t * ls0, u32 * next0)
108 {
109   ip6_address_t *new_dst0;
110
111   if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
112                      sr0->type != ROUTING_HEADER_TYPE_SR))
113     {
114       *next0 = SRV6_AM_LOCALSID_NEXT_ERROR;
115       return;
116     }
117
118   if (PREDICT_FALSE (sr0->segments_left == 0))
119     {
120       *next0 = SRV6_AM_LOCALSID_NEXT_ERROR;
121       return;
122     }
123
124   /* Decrement Segments Left */
125   sr0->segments_left -= 1;
126
127   /* Set Destination Address to Last Segment (index 0) */
128   new_dst0 = (ip6_address_t *) (sr0->segments);
129   ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
130   ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
131
132   /* Set Xconnect adjacency to VNF */
133   vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
134 }
135
136 /**
137  * @brief Graph node for applying SRv6 masquerading.
138  */
139 static uword
140 srv6_am_localsid_fn (vlib_main_t * vm,
141                      vlib_node_runtime_t * node, vlib_frame_t * frame)
142 {
143   ip6_sr_main_t *sm = &sr_main;
144   u32 n_left_from, next_index, *from, *to_next;
145   u32 cnt_packets = 0;
146
147   from = vlib_frame_vector_args (frame);
148   n_left_from = frame->n_vectors;
149   next_index = node->cached_next_index;
150
151   u32 thread_index = vm->thread_index;
152
153   while (n_left_from > 0)
154     {
155       u32 n_left_to_next;
156
157       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
158
159       /* TODO: Dual/quad loop */
160
161       while (n_left_from > 0 && n_left_to_next > 0)
162         {
163           u32 bi0;
164           vlib_buffer_t *b0;
165           ip6_header_t *ip0 = 0;
166           ip6_sr_header_t *sr0;
167           ip6_sr_localsid_t *ls0;
168           u32 next0 = SRV6_AM_LOCALSID_NEXT_REWRITE;
169
170           bi0 = from[0];
171           to_next[0] = bi0;
172           from += 1;
173           to_next += 1;
174           n_left_from -= 1;
175           n_left_to_next -= 1;
176
177           b0 = vlib_get_buffer (vm, bi0);
178           ip0 = vlib_buffer_get_current (b0);
179           sr0 = (ip6_sr_header_t *) (ip0 + 1);
180
181           /* Lookup the SR End behavior based on IP DA (adj) */
182           ls0 = pool_elt_at_index (sm->localsids,
183                                    vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
184
185           /* SRH processing */
186           end_am_processing (b0, ip0, sr0, ls0, &next0);
187
188           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
189             {
190               srv6_am_localsid_trace_t *tr =
191                 vlib_add_trace (vm, node, b0, sizeof *tr);
192               tr->localsid_index = ls0 - sm->localsids;
193             }
194
195           /* This increments the SRv6 per LocalSID counters. */
196           vlib_increment_combined_counter (((next0 ==
197                                              SRV6_AM_LOCALSID_NEXT_ERROR) ?
198                                             &(sm->sr_ls_invalid_counters) :
199                                             &(sm->sr_ls_valid_counters)),
200                                            thread_index, ls0 - sm->localsids,
201                                            1, vlib_buffer_length_in_chain (vm,
202                                                                            b0));
203
204           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
205                                            n_left_to_next, bi0, next0);
206
207           cnt_packets++;
208         }
209
210       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
211     }
212
213   return frame->n_vectors;
214 }
215
216 /* *INDENT-OFF* */
217 VLIB_REGISTER_NODE (srv6_am_localsid_node) = {
218   .function = srv6_am_localsid_fn,
219   .name = "srv6-am-localsid",
220   .vector_size = sizeof (u32),
221   .format_trace = format_srv6_am_localsid_trace,
222   .type = VLIB_NODE_TYPE_INTERNAL,
223   .n_next_nodes = SRV6_AM_LOCALSID_N_NEXT,
224   .next_nodes = {
225     [SRV6_AM_LOCALSID_NEXT_REWRITE] = "ip6-rewrite",
226     [SRV6_AM_LOCALSID_NEXT_ERROR] = "error-drop",
227   },
228 };
229 /* *INDENT-ON* */
230
231
232 /******************************* Rewriting node *******************************/
233
234 /**
235  * @brief SRv6 de-masquerading.
236  */
237 static_always_inline void
238 end_am_rewriting (vlib_node_runtime_t * node,
239                   vlib_buffer_t * b0,
240                   ip6_header_t * ip0, ip6_sr_header_t * sr0, u32 * next0)
241 {
242   if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
243                      sr0->type != ROUTING_HEADER_TYPE_SR))
244     {
245       b0->error = node->errors[SRV6_AM_REWRITE_COUNTER_NO_SRH];
246       *next0 = SRV6_AM_REWRITE_NEXT_ERROR;
247       return;
248     }
249
250   /* Restore Destination Address to active segment (index SL) */
251   if (sr0->segments_left != 0)
252     {
253       ip6_address_t *new_dst0;
254       new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
255       ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
256       ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
257     }
258 }
259
260 /**
261  * @brief Graph node for applying SRv6 de-masquerading.
262  */
263 static uword
264 srv6_am_rewrite_fn (vlib_main_t * vm,
265                     vlib_node_runtime_t * node, vlib_frame_t * frame)
266 {
267   u32 n_left_from, next_index, *from, *to_next;
268   u32 cnt_packets = 0;
269
270   from = vlib_frame_vector_args (frame);
271   n_left_from = frame->n_vectors;
272   next_index = node->cached_next_index;
273
274   while (n_left_from > 0)
275     {
276       u32 n_left_to_next;
277
278       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
279
280       /* TODO: Dual/quad loop */
281
282       while (n_left_from > 0 && n_left_to_next > 0)
283         {
284           u32 bi0;
285           vlib_buffer_t *b0;
286           ip6_header_t *ip0 = 0;
287           ip6_sr_header_t *sr0;
288           u32 next0 = SRV6_AM_REWRITE_NEXT_LOOKUP;
289
290           bi0 = from[0];
291           to_next[0] = bi0;
292           from += 1;
293           to_next += 1;
294           n_left_from -= 1;
295           n_left_to_next -= 1;
296
297           b0 = vlib_get_buffer (vm, bi0);
298           ip0 = vlib_buffer_get_current (b0);
299           sr0 = (ip6_sr_header_t *) (ip0 + 1);
300
301           /* SRH processing */
302           end_am_rewriting (node, b0, ip0, sr0, &next0);
303
304           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
305               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
306             {
307               srv6_am_rewrite_trace_t *tr =
308                 vlib_add_trace (vm, node, b0, sizeof *tr);
309               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
310                                 sizeof tr->src.as_u8);
311               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
312                                 sizeof tr->dst.as_u8);
313             }
314
315           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
316                                            n_left_to_next, bi0, next0);
317
318           cnt_packets++;
319         }
320
321       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
322     }
323
324   /* Update counters */
325   vlib_node_increment_counter (vm, srv6_am_rewrite_node.index,
326                                SRV6_AM_REWRITE_COUNTER_PROCESSED,
327                                cnt_packets);
328
329   return frame->n_vectors;
330 }
331
332 /* *INDENT-OFF* */
333 VLIB_REGISTER_NODE (srv6_am_rewrite_node) = {
334   .function = srv6_am_rewrite_fn,
335   .name = "srv6-am-rewrite",
336   .vector_size = sizeof (u32),
337   .format_trace = format_srv6_am_rewrite_trace,
338   .type = VLIB_NODE_TYPE_INTERNAL,
339   .n_errors = SRV6_AM_REWRITE_N_COUNTERS,
340   .error_strings = srv6_am_rewrite_counter_strings,
341   .n_next_nodes = SRV6_AM_REWRITE_N_NEXT,
342   .next_nodes = {
343       [SRV6_AM_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
344       [SRV6_AM_REWRITE_NEXT_ERROR] = "error-drop",
345   },
346 };
347 /* *INDENT-ON* */
348
349 /*
350 * fd.io coding-style-patch-verification: ON
351 *
352 * Local Variables:
353 * eval: (c-set-style "gnu")
354 * End:
355 */