udp: fix csum computation when offload disabled
[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
146   from = vlib_frame_vector_args (frame);
147   n_left_from = frame->n_vectors;
148   next_index = node->cached_next_index;
149
150   u32 thread_index = vm->thread_index;
151
152   while (n_left_from > 0)
153     {
154       u32 n_left_to_next;
155
156       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
157
158       /* TODO: Dual/quad loop */
159
160       while (n_left_from > 0 && n_left_to_next > 0)
161         {
162           u32 bi0;
163           vlib_buffer_t *b0;
164           ip6_header_t *ip0 = 0;
165           ip6_sr_header_t *sr0;
166           ip6_sr_localsid_t *ls0;
167           u32 next0 = SRV6_AM_LOCALSID_NEXT_REWRITE;
168
169           bi0 = from[0];
170           to_next[0] = bi0;
171           from += 1;
172           to_next += 1;
173           n_left_from -= 1;
174           n_left_to_next -= 1;
175
176           b0 = vlib_get_buffer (vm, bi0);
177           ip0 = vlib_buffer_get_current (b0);
178           sr0 = (ip6_sr_header_t *) (ip0 + 1);
179
180           /* Lookup the SR End behavior based on IP DA (adj) */
181           ls0 = pool_elt_at_index (sm->localsids,
182                                    vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
183
184           /* SRH processing */
185           end_am_processing (b0, ip0, sr0, ls0, &next0);
186
187           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
188             {
189               srv6_am_localsid_trace_t *tr =
190                 vlib_add_trace (vm, node, b0, sizeof *tr);
191               tr->localsid_index = ls0 - sm->localsids;
192             }
193
194           /* This increments the SRv6 per LocalSID counters. */
195           vlib_increment_combined_counter (((next0 ==
196                                              SRV6_AM_LOCALSID_NEXT_ERROR) ?
197                                             &(sm->sr_ls_invalid_counters) :
198                                             &(sm->sr_ls_valid_counters)),
199                                            thread_index, ls0 - sm->localsids,
200                                            1, vlib_buffer_length_in_chain (vm,
201                                                                            b0));
202
203           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
204                                            n_left_to_next, bi0, next0);
205         }
206
207       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
208     }
209
210   return frame->n_vectors;
211 }
212
213 VLIB_REGISTER_NODE (srv6_am_localsid_node) = {
214   .function = srv6_am_localsid_fn,
215   .name = "srv6-am-localsid",
216   .vector_size = sizeof (u32),
217   .format_trace = format_srv6_am_localsid_trace,
218   .type = VLIB_NODE_TYPE_INTERNAL,
219   .n_next_nodes = SRV6_AM_LOCALSID_N_NEXT,
220   .next_nodes = {
221     [SRV6_AM_LOCALSID_NEXT_REWRITE] = "ip6-rewrite",
222     [SRV6_AM_LOCALSID_NEXT_ERROR] = "error-drop",
223   },
224 };
225
226
227 /******************************* Rewriting node *******************************/
228
229 /**
230  * @brief SRv6 de-masquerading.
231  */
232 static_always_inline void
233 end_am_rewriting (vlib_node_runtime_t * node,
234                   vlib_buffer_t * b0,
235                   ip6_header_t * ip0, ip6_sr_header_t * sr0, u32 * next0)
236 {
237   if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
238                      sr0->type != ROUTING_HEADER_TYPE_SR))
239     {
240       b0->error = node->errors[SRV6_AM_REWRITE_COUNTER_NO_SRH];
241       *next0 = SRV6_AM_REWRITE_NEXT_ERROR;
242       return;
243     }
244
245   /* Restore Destination Address to active segment (index SL) */
246   if (sr0->segments_left != 0)
247     {
248       ip6_address_t *new_dst0;
249       new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
250       ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
251       ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
252     }
253 }
254
255 /**
256  * @brief Graph node for applying SRv6 de-masquerading.
257  */
258 static uword
259 srv6_am_rewrite_fn (vlib_main_t * vm,
260                     vlib_node_runtime_t * node, vlib_frame_t * frame)
261 {
262   u32 n_left_from, next_index, *from, *to_next;
263   u32 cnt_packets = 0;
264
265   from = vlib_frame_vector_args (frame);
266   n_left_from = frame->n_vectors;
267   next_index = node->cached_next_index;
268
269   while (n_left_from > 0)
270     {
271       u32 n_left_to_next;
272
273       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
274
275       /* TODO: Dual/quad loop */
276
277       while (n_left_from > 0 && n_left_to_next > 0)
278         {
279           u32 bi0;
280           vlib_buffer_t *b0;
281           ip6_header_t *ip0 = 0;
282           ip6_sr_header_t *sr0;
283           u32 next0 = SRV6_AM_REWRITE_NEXT_LOOKUP;
284
285           bi0 = from[0];
286           to_next[0] = bi0;
287           from += 1;
288           to_next += 1;
289           n_left_from -= 1;
290           n_left_to_next -= 1;
291
292           b0 = vlib_get_buffer (vm, bi0);
293           ip0 = vlib_buffer_get_current (b0);
294           sr0 = (ip6_sr_header_t *) (ip0 + 1);
295
296           /* SRH processing */
297           end_am_rewriting (node, b0, ip0, sr0, &next0);
298
299           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
300               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
301             {
302               srv6_am_rewrite_trace_t *tr =
303                 vlib_add_trace (vm, node, b0, sizeof *tr);
304               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
305                                 sizeof tr->src.as_u8);
306               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
307                                 sizeof tr->dst.as_u8);
308             }
309
310           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
311                                            n_left_to_next, bi0, next0);
312
313           cnt_packets++;
314         }
315
316       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
317     }
318
319   /* Update counters */
320   vlib_node_increment_counter (vm, srv6_am_rewrite_node.index,
321                                SRV6_AM_REWRITE_COUNTER_PROCESSED,
322                                cnt_packets);
323
324   return frame->n_vectors;
325 }
326
327 VLIB_REGISTER_NODE (srv6_am_rewrite_node) = {
328   .function = srv6_am_rewrite_fn,
329   .name = "srv6-am-rewrite",
330   .vector_size = sizeof (u32),
331   .format_trace = format_srv6_am_rewrite_trace,
332   .type = VLIB_NODE_TYPE_INTERNAL,
333   .n_errors = SRV6_AM_REWRITE_N_COUNTERS,
334   .error_strings = srv6_am_rewrite_counter_strings,
335   .n_next_nodes = SRV6_AM_REWRITE_N_NEXT,
336   .next_nodes = {
337       [SRV6_AM_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
338       [SRV6_AM_REWRITE_NEXT_ERROR] = "error-drop",
339   },
340 };
341
342 /*
343 * fd.io coding-style-patch-verification: ON
344 *
345 * Local Variables:
346 * eval: (c-set-style "gnu")
347 * End:
348 */