dd2b1c4d542717ea109f8563e30b732e5c4ee143
[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 /* *INDENT-OFF* */
214 VLIB_REGISTER_NODE (srv6_am_localsid_node) = {
215   .function = srv6_am_localsid_fn,
216   .name = "srv6-am-localsid",
217   .vector_size = sizeof (u32),
218   .format_trace = format_srv6_am_localsid_trace,
219   .type = VLIB_NODE_TYPE_INTERNAL,
220   .n_next_nodes = SRV6_AM_LOCALSID_N_NEXT,
221   .next_nodes = {
222     [SRV6_AM_LOCALSID_NEXT_REWRITE] = "ip6-rewrite",
223     [SRV6_AM_LOCALSID_NEXT_ERROR] = "error-drop",
224   },
225 };
226 /* *INDENT-ON* */
227
228
229 /******************************* Rewriting node *******************************/
230
231 /**
232  * @brief SRv6 de-masquerading.
233  */
234 static_always_inline void
235 end_am_rewriting (vlib_node_runtime_t * node,
236                   vlib_buffer_t * b0,
237                   ip6_header_t * ip0, ip6_sr_header_t * sr0, u32 * next0)
238 {
239   if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
240                      sr0->type != ROUTING_HEADER_TYPE_SR))
241     {
242       b0->error = node->errors[SRV6_AM_REWRITE_COUNTER_NO_SRH];
243       *next0 = SRV6_AM_REWRITE_NEXT_ERROR;
244       return;
245     }
246
247   /* Restore Destination Address to active segment (index SL) */
248   if (sr0->segments_left != 0)
249     {
250       ip6_address_t *new_dst0;
251       new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
252       ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
253       ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
254     }
255 }
256
257 /**
258  * @brief Graph node for applying SRv6 de-masquerading.
259  */
260 static uword
261 srv6_am_rewrite_fn (vlib_main_t * vm,
262                     vlib_node_runtime_t * node, vlib_frame_t * frame)
263 {
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           ip6_header_t *ip0 = 0;
284           ip6_sr_header_t *sr0;
285           u32 next0 = SRV6_AM_REWRITE_NEXT_LOOKUP;
286
287           bi0 = from[0];
288           to_next[0] = bi0;
289           from += 1;
290           to_next += 1;
291           n_left_from -= 1;
292           n_left_to_next -= 1;
293
294           b0 = vlib_get_buffer (vm, bi0);
295           ip0 = vlib_buffer_get_current (b0);
296           sr0 = (ip6_sr_header_t *) (ip0 + 1);
297
298           /* SRH processing */
299           end_am_rewriting (node, b0, ip0, sr0, &next0);
300
301           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
302               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
303             {
304               srv6_am_rewrite_trace_t *tr =
305                 vlib_add_trace (vm, node, b0, sizeof *tr);
306               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
307                                 sizeof tr->src.as_u8);
308               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
309                                 sizeof tr->dst.as_u8);
310             }
311
312           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
313                                            n_left_to_next, bi0, next0);
314
315           cnt_packets++;
316         }
317
318       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
319     }
320
321   /* Update counters */
322   vlib_node_increment_counter (vm, srv6_am_rewrite_node.index,
323                                SRV6_AM_REWRITE_COUNTER_PROCESSED,
324                                cnt_packets);
325
326   return frame->n_vectors;
327 }
328
329 /* *INDENT-OFF* */
330 VLIB_REGISTER_NODE (srv6_am_rewrite_node) = {
331   .function = srv6_am_rewrite_fn,
332   .name = "srv6-am-rewrite",
333   .vector_size = sizeof (u32),
334   .format_trace = format_srv6_am_rewrite_trace,
335   .type = VLIB_NODE_TYPE_INTERNAL,
336   .n_errors = SRV6_AM_REWRITE_N_COUNTERS,
337   .error_strings = srv6_am_rewrite_counter_strings,
338   .n_next_nodes = SRV6_AM_REWRITE_N_NEXT,
339   .next_nodes = {
340       [SRV6_AM_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
341       [SRV6_AM_REWRITE_NEXT_ERROR] = "error-drop",
342   },
343 };
344 /* *INDENT-ON* */
345
346 /*
347 * fd.io coding-style-patch-verification: ON
348 *
349 * Local Variables:
350 * eval: (c-set-style "gnu")
351 * End:
352 */