VPP-1507: Added binary api to dump configured ip_punt_redirect
[vpp.git] / src / vnet / lawful-intercept / 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
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vppinfra/error.h>
19
20 #include <vnet/lawful-intercept/lawful_intercept.h>
21
22 #include <vppinfra/error.h>
23 #include <vppinfra/elog.h>
24
25 vlib_node_registration_t li_hit_node;
26
27 typedef struct
28 {
29   u32 next_index;
30 } li_hit_trace_t;
31
32 /* packet trace format function */
33 static u8 *
34 format_li_hit_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   li_hit_trace_t *t = va_arg (*args, li_hit_trace_t *);
39
40   s = format (s, "LI_HIT: next index %d", t->next_index);
41
42   return s;
43 }
44
45 vlib_node_registration_t li_hit_node;
46
47 #define foreach_li_hit_error                                    \
48 _(HITS, "LI packets processed")                                 \
49 _(NO_COLLECTOR, "No collector configured")                      \
50 _(BUFFER_ALLOCATION_FAILURE, "Buffer allocation failure")
51
52 typedef enum
53 {
54 #define _(sym,str) LI_HIT_ERROR_##sym,
55   foreach_li_hit_error
56 #undef _
57     LI_HIT_N_ERROR,
58 } li_hit_error_t;
59
60 static char *li_hit_error_strings[] = {
61 #define _(sym,string) string,
62   foreach_li_hit_error
63 #undef _
64 };
65
66 typedef enum
67 {
68   LI_HIT_NEXT_ETHERNET,
69   LI_HIT_N_NEXT,
70 } li_hit_next_t;
71
72 static uword
73 li_hit_node_fn (vlib_main_t * vm,
74                 vlib_node_runtime_t * node, vlib_frame_t * frame)
75 {
76   u32 n_left_from, *from, *to_next;
77   li_hit_next_t next_index;
78   vlib_frame_t *int_frame = 0;
79   u32 *to_int_next = 0;
80   li_main_t *lm = &li_main;
81
82   from = vlib_frame_vector_args (frame);
83   n_left_from = frame->n_vectors;
84   next_index = node->cached_next_index;
85
86   if (PREDICT_FALSE (vec_len (lm->collectors) == 0))
87     {
88       vlib_node_increment_counter (vm, li_hit_node.index,
89                                    LI_HIT_ERROR_NO_COLLECTOR, n_left_from);
90     }
91   else
92     {
93       /* The intercept frame... */
94       int_frame = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
95       to_int_next = vlib_frame_vector_args (int_frame);
96     }
97
98   while (n_left_from > 0)
99     {
100       u32 n_left_to_next;
101
102       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
103
104 #if 0
105       while (n_left_from >= 4 && n_left_to_next >= 2)
106         {
107           u32 next0 = LI_HIT_NEXT_INTERFACE_OUTPUT;
108           u32 next1 = LI_HIT_NEXT_INTERFACE_OUTPUT;
109           u32 sw_if_index0, sw_if_index1;
110           u8 tmp0[6], tmp1[6];
111           ethernet_header_t *en0, *en1;
112           u32 bi0, bi1;
113           vlib_buffer_t *b0, *b1;
114
115           /* Prefetch next iteration. */
116           {
117             vlib_buffer_t *p2, *p3;
118
119             p2 = vlib_get_buffer (vm, from[2]);
120             p3 = vlib_get_buffer (vm, from[3]);
121
122             vlib_prefetch_buffer_header (p2, LOAD);
123             vlib_prefetch_buffer_header (p3, LOAD);
124
125             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
126             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
127           }
128
129           /* speculatively enqueue b0 and b1 to the current next frame */
130           to_next[0] = bi0 = from[0];
131           to_next[1] = bi1 = from[1];
132           from += 2;
133           to_next += 2;
134           n_left_from -= 2;
135           n_left_to_next -= 2;
136
137           b0 = vlib_get_buffer (vm, bi0);
138           b1 = vlib_get_buffer (vm, bi1);
139
140           /* $$$$$ Dual loop: process 2 x packets here $$$$$ */
141           ASSERT (b0->current_data == 0);
142           ASSERT (b1->current_data == 0);
143
144           en0 = vlib_buffer_get_current (b0);
145           en1 = vlib_buffer_get_current (b1);
146
147           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
148           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
149
150           /* Send pkt back out the RX interface */
151           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
152           vnet_buffer (b1)->sw_if_index[VLIB_TX] = sw_if_index1;
153
154           /* $$$$$ End of processing 2 x packets $$$$$ */
155
156           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
157             {
158               if (b0->flags & VLIB_BUFFER_IS_TRACED)
159                 {
160                   li_hit_trace_t *t =
161                     vlib_add_trace (vm, node, b0, sizeof (*t));
162                   t->sw_if_index = sw_if_index0;
163                   t->next_index = next0;
164                 }
165               if (b1->flags & VLIB_BUFFER_IS_TRACED)
166                 {
167                   li_hit_trace_t *t =
168                     vlib_add_trace (vm, node, b1, sizeof (*t));
169                   t->sw_if_index = sw_if_index1;
170                   t->next_index = next1;
171                 }
172             }
173
174           /* verify speculative enqueues, maybe switch current next frame */
175           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
176                                            to_next, n_left_to_next,
177                                            bi0, bi1, next0, next1);
178         }
179 #endif /* $$$ dual-loop off */
180
181       while (n_left_from > 0 && n_left_to_next > 0)
182         {
183           u32 bi0;
184           vlib_buffer_t *b0;
185           vlib_buffer_t *c0;
186           ip4_udp_header_t *iu0;
187           ip4_header_t *ip0;
188           udp_header_t *udp0;
189           u32 next0 = LI_HIT_NEXT_ETHERNET;
190
191           /* speculatively enqueue b0 to the current next frame */
192           bi0 = from[0];
193           to_next[0] = bi0;
194           from += 1;
195           to_next += 1;
196           n_left_from -= 1;
197           n_left_to_next -= 1;
198
199           b0 = vlib_get_buffer (vm, bi0);
200           if (PREDICT_TRUE (to_int_next != 0))
201             {
202               /* Make an intercept copy. This can fail. */
203               c0 = vlib_buffer_copy (vm, b0);
204
205               if (PREDICT_FALSE (c0 == 0))
206                 {
207                   vlib_node_increment_counter
208                     (vm, node->node_index,
209                      LI_HIT_ERROR_BUFFER_ALLOCATION_FAILURE, 1);
210                   goto skip;
211                 }
212
213               vlib_buffer_advance (c0, -sizeof (*iu0));
214
215               iu0 = vlib_buffer_get_current (c0);
216               ip0 = &iu0->ip4;
217
218               ip0->ip_version_and_header_length = 0x45;
219               ip0->ttl = 254;
220               ip0->protocol = IP_PROTOCOL_UDP;
221
222               ip0->src_address.as_u32 = lm->src_addrs[0].as_u32;
223               ip0->dst_address.as_u32 = lm->collectors[0].as_u32;
224               ip0->length = vlib_buffer_length_in_chain (vm, c0);
225               ip0->checksum = ip4_header_checksum (ip0);
226
227               udp0 = &iu0->udp;
228               udp0->src_port = udp0->dst_port =
229                 clib_host_to_net_u16 (lm->ports[0]);
230               udp0->checksum = 0;
231               udp0->length =
232                 clib_net_to_host_u16 (vlib_buffer_length_in_chain (vm, b0));
233
234               to_int_next[0] = vlib_get_buffer_index (vm, c0);
235               to_int_next++;
236             }
237
238         skip:
239           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
240                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
241             {
242               li_hit_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
243               t->next_index = next0;
244             }
245
246           /* verify speculative enqueue, maybe switch current next frame */
247           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
248                                            to_next, n_left_to_next,
249                                            bi0, next0);
250         }
251
252       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
253     }
254
255   if (int_frame)
256     {
257       int_frame->n_vectors = frame->n_vectors;
258       vlib_put_frame_to_node (vm, ip4_lookup_node.index, int_frame);
259     }
260
261   vlib_node_increment_counter (vm, li_hit_node.index,
262                                LI_HIT_ERROR_HITS, frame->n_vectors);
263   return frame->n_vectors;
264 }
265
266 /* *INDENT-OFF* */
267 VLIB_REGISTER_NODE (li_hit_node) = {
268   .function = li_hit_node_fn,
269   .name = "li-hit",
270   .vector_size = sizeof (u32),
271   .format_trace = format_li_hit_trace,
272   .type = VLIB_NODE_TYPE_INTERNAL,
273
274   .n_errors = ARRAY_LEN(li_hit_error_strings),
275   .error_strings = li_hit_error_strings,
276
277   .n_next_nodes = LI_HIT_N_NEXT,
278
279   /* edit / add dispositions here */
280   .next_nodes = {
281         [LI_HIT_NEXT_ETHERNET] = "ethernet-input-not-l2",
282   },
283 };
284 /* *INDENT-ON* */
285
286 VLIB_NODE_FUNCTION_MULTIARCH (li_hit_node, li_hit_node_fn)
287 /*
288  * fd.io coding-style-patch-verification: ON
289  *
290  * Local Variables:
291  * eval: (c-set-style "gnu")
292  * End:
293  */