Driver level time-based src mac filter
[vpp.git] / src / plugins / mactime / node.c
1 /*
2  * node.c - skeleton vpp engine plug-in dual-loop node skeleton
3  *
4  * Copyright (c) <current-year> <your-organization>
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <vlib/vlib.h>
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vppinfra/error.h>
21 #include <mactime/mactime.h>
22
23 typedef struct
24 {
25   u32 next_index;
26   u32 device_index;
27   u8 src_mac[6];
28   u8 device_name[64];
29 } mactime_trace_t;
30
31 static u8 *
32 format_mac_address (u8 * s, va_list * args)
33 {
34   u8 *a = va_arg (*args, u8 *);
35   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
36                  a[0], a[1], a[2], a[3], a[4], a[5]);
37 }
38
39 vlib_node_registration_t mactime_node;
40
41 #define foreach_mactime_error                   \
42 _(DROP, "Dropped packets")                      \
43 _(OK, "Permitted packets")
44
45 typedef enum
46 {
47 #define _(sym,str) MACTIME_ERROR_##sym,
48   foreach_mactime_error
49 #undef _
50     MACTIME_N_ERROR,
51 } mactime_error_t;
52
53 static char *mactime_error_strings[] = {
54 #define _(sym,string) string,
55   foreach_mactime_error
56 #undef _
57 };
58
59 typedef enum
60 {
61   MACTIME_NEXT_ETHERNET_INPUT,
62   MACTIME_NEXT_DROP,
63   MACTIME_N_NEXT,
64 } mactime_next_t;
65
66 /* packet trace format function */
67 static u8 *
68 format_mactime_trace (u8 * s, va_list * args)
69 {
70   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
71   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
72   mactime_trace_t *t = va_arg (*args, mactime_trace_t *);
73
74   s = format (s, "MACTIME: src mac %U device %s result %s\n",
75               format_mac_address, t->src_mac,
76               (t->device_index != ~0) ? t->device_name : (u8 *) "unknown",
77               t->next_index == MACTIME_NEXT_ETHERNET_INPUT ? "pass" : "drop");
78   return s;
79 }
80
81 static uword
82 mactime_node_fn (vlib_main_t * vm,
83                  vlib_node_runtime_t * node, vlib_frame_t * frame)
84 {
85   u32 n_left_from, *from, *to_next;
86   mactime_next_t next_index;
87   mactime_main_t *mm = &mactime_main;
88   mactime_device_t *dp;
89   clib_bihash_kv_8_8_t kv;
90   clib_bihash_8_8_t *lut = &mm->lookup_table;
91   u32 packets_ok = 0, packets_dropped = 0;
92   f64 now;
93   u32 thread_index = vm->thread_index;
94
95   now = clib_timebase_now (&mm->timebase);
96
97   if (PREDICT_FALSE ((now - mm->sunday_midnight) > 86400.0 * 7.0))
98     mm->sunday_midnight = clib_timebase_find_sunday_midnight (now);
99
100   from = vlib_frame_vector_args (frame);
101   n_left_from = frame->n_vectors;
102   next_index = node->cached_next_index;
103
104   while (n_left_from > 0)
105     {
106       u32 n_left_to_next;
107
108       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
109
110 #if 0
111       while (n_left_from >= 4 && n_left_to_next >= 2)
112         {
113           u32 next0 = MACTIME_NEXT_INTERFACE_OUTPUT;
114           u32 next1 = MACTIME_NEXT_INTERFACE_OUTPUT;
115           u32 sw_if_index0, sw_if_index1;
116           u8 tmp0[6], tmp1[6];
117           ethernet_header_t *en0, *en1;
118           u32 bi0, bi1;
119           vlib_buffer_t *b0, *b1;
120
121           /* Prefetch next iteration. */
122           {
123             vlib_buffer_t *p2, *p3;
124
125             p2 = vlib_get_buffer (vm, from[2]);
126             p3 = vlib_get_buffer (vm, from[3]);
127
128             vlib_prefetch_buffer_header (p2, LOAD);
129             vlib_prefetch_buffer_header (p3, LOAD);
130
131             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
132             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
133           }
134
135           /* speculatively enqueue b0 and b1 to the current next frame */
136           to_next[0] = bi0 = from[0];
137           to_next[1] = bi1 = from[1];
138           from += 2;
139           to_next += 2;
140           n_left_from -= 2;
141           n_left_to_next -= 2;
142
143           b0 = vlib_get_buffer (vm, bi0);
144           b1 = vlib_get_buffer (vm, bi1);
145
146           ASSERT (b0->current_data == 0);
147           ASSERT (b1->current_data == 0);
148
149           en0 = vlib_buffer_get_current (b0);
150           en1 = vlib_buffer_get_current (b1);
151
152           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
153           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
154
155           /* Send pkt back out the RX interface */
156           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
157           vnet_buffer (b1)->sw_if_index[VLIB_TX] = sw_if_index1;
158
159           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
160             {
161               if (b0->flags & VLIB_BUFFER_IS_TRACED)
162                 {
163                   mactime_trace_t *t =
164                     vlib_add_trace (vm, node, b0, sizeof (*t));
165                   t->sw_if_index = sw_if_index0;
166                   t->next_index = next0;
167                   clib_memcpy (t->new_src_mac, en0->src_address,
168                                sizeof (t->new_src_mac));
169                   clib_memcpy (t->new_dst_mac, en0->dst_address,
170                                sizeof (t->new_dst_mac));
171                 }
172               if (b1->flags & VLIB_BUFFER_IS_TRACED)
173                 {
174                   mactime_trace_t *t =
175                     vlib_add_trace (vm, node, b1, sizeof (*t));
176                   t->sw_if_index = sw_if_index1;
177                   t->next_index = next1;
178                   clib_memcpy (t->new_src_mac, en1->src_address,
179                                sizeof (t->new_src_mac));
180                   clib_memcpy (t->new_dst_mac, en1->dst_address,
181                                sizeof (t->new_dst_mac));
182                 }
183             }
184
185           /* verify speculative enqueues, maybe switch current next frame */
186           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
187                                            to_next, n_left_to_next,
188                                            bi0, bi1, next0, next1);
189         }
190 #endif /* dual loop */
191
192       while (n_left_from > 0 && n_left_to_next > 0)
193         {
194           u32 bi0;
195           vlib_buffer_t *b0;
196           u32 next0 = MACTIME_NEXT_ETHERNET_INPUT;
197           u32 device_index0;
198           ethernet_header_t *en0;
199           int i;
200
201           /* speculatively enqueue b0 to the current next frame */
202           bi0 = from[0];
203           to_next[0] = bi0;
204           from += 1;
205           to_next += 1;
206           n_left_from -= 1;
207           n_left_to_next -= 1;
208
209           b0 = vlib_get_buffer (vm, bi0);
210
211           vlib_buffer_advance (b0, -(word) vnet_buffer (b0)->l2_hdr_offset);
212
213           en0 = vlib_buffer_get_current (b0);
214           kv.key = 0;
215           clib_memcpy (&kv.key, en0->src_address, 6);
216
217
218           /* Lookup the src mac address */
219           if (clib_bihash_search_8_8 (lut, &kv, &kv) < 0)
220             {
221               device_index0 = ~0;
222               dp = 0;
223               goto trace0;
224             }
225           else
226             device_index0 = kv.value;
227
228           dp = pool_elt_at_index (mm->devices, device_index0);
229
230           /* Static drop / allow? */
231           if (PREDICT_FALSE
232               (dp->flags &
233                (MACTIME_DEVICE_FLAG_STATIC_DROP
234                 | MACTIME_DEVICE_FLAG_STATIC_ALLOW)))
235             {
236               if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_DROP)
237                 {
238                   next0 = MACTIME_NEXT_DROP;
239                   vlib_increment_simple_counter
240                     (&mm->drop_counters, thread_index, dp - mm->devices, 1);
241                   packets_dropped++;
242                 }
243               else              /* note next0 set to allow */
244                 {
245                   vlib_increment_simple_counter
246                     (&mm->allow_counters, thread_index, dp - mm->devices, 1);
247                   packets_ok++;
248                 }
249               goto trace0;
250             }
251
252           /* Known device, see if traffic allowed at the moment */
253           for (i = 0; i < vec_len (dp->ranges); i++)
254             {
255               clib_timebase_range_t *r = dp->ranges + i;
256               f64 start0, end0;
257
258               start0 = r->start + mm->sunday_midnight;
259               end0 = r->end + mm->sunday_midnight;
260               /* Packet within time range */
261               if (now >= start0 && now <= end0)
262                 {
263                   /* And it's a drop range, drop it */
264                   if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_DROP)
265                     {
266                       vlib_increment_simple_counter
267                         (&mm->drop_counters, thread_index,
268                          dp - mm->devices, 1);
269                       packets_dropped++;
270                       next0 = MACTIME_NEXT_DROP;
271                     }
272                   else          /* it's an allow range, allow it */
273                     {
274                       vlib_increment_simple_counter
275                         (&mm->allow_counters, thread_index,
276                          dp - mm->devices, 1);
277                       packets_ok++;
278                     }
279                   goto trace0;
280                 }
281             }
282           /*
283            * Didn't hit a range, so *drop* if allow configured, or
284            * *allow* if drop configured.
285            */
286           if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
287             {
288               next0 = MACTIME_NEXT_DROP;
289               vlib_increment_simple_counter
290                 (&mm->drop_counters, thread_index, dp - mm->devices, 1);
291               packets_dropped++;
292             }
293           else
294             {
295               vlib_increment_simple_counter
296                 (&mm->allow_counters, thread_index, dp - mm->devices, 1);
297               packets_ok++;
298             }
299
300         trace0:
301           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
302                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
303             {
304               mactime_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
305               clib_memcpy (t->src_mac, en0->src_address, sizeof (t->src_mac));
306
307               t->next_index = next0;
308               t->device_index = device_index0;
309
310               if (dp)
311                 {
312                   clib_memcpy (t->device_name, dp->device_name,
313                                ARRAY_LEN (t->device_name));
314                   t->device_name[ARRAY_LEN (t->device_name) - 1] = 0;
315                 }
316             }
317
318           /* verify speculative enqueue, maybe switch current next frame */
319           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
320                                            to_next, n_left_to_next,
321                                            bi0, next0);
322         }
323
324       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
325     }
326
327   vlib_node_increment_counter (vm, mactime_node.index,
328                                MACTIME_ERROR_DROP, packets_dropped);
329   vlib_node_increment_counter (vm, mactime_node.index,
330                                MACTIME_ERROR_OK, packets_ok);
331   return frame->n_vectors;
332 }
333
334 /* *INDENT-OFF* */
335 VLIB_REGISTER_NODE (mactime_node) =
336 {
337   .function = mactime_node_fn,
338   .name = "mactime",
339   .vector_size = sizeof (u32),
340   .format_trace = format_mactime_trace,
341   .type = VLIB_NODE_TYPE_INTERNAL,
342
343   .n_errors = ARRAY_LEN(mactime_error_strings),
344   .error_strings = mactime_error_strings,
345
346   .n_next_nodes = MACTIME_N_NEXT,
347
348   /* edit / add dispositions here */
349   .next_nodes =
350   {
351     [MACTIME_NEXT_ETHERNET_INPUT] = "ethernet-input",
352     [MACTIME_NEXT_DROP] = "error-drop",
353   },
354 };
355 /* *INDENT-ON* */
356
357 /*
358  * fd.io coding-style-patch-verification: ON
359  *
360  * Local Variables:
361  * eval: (c-set-style "gnu")
362  * End:
363  */