FD.io VPP  v19.04.1-1-ge4a0f9f
Vector Packet Processing
tcp_syn_filter4.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2019 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 <vnet/pg/pg.h>
19 #include <vppinfra/error.h>
20 #include <vnet/feature/feature.h>
21 #include <vnet/ip/ip.h>
22 #include <vppinfra/xxhash.h>
23 
24 typedef struct
25 {
30 
31 typedef struct
32 {
34  int not_a_syn;
37 
38 /* packet trace format function */
39 static u8 *
40 format_syn_filter4_trace (u8 * s, va_list * args)
41 {
42  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
43  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
44  syn_filter4_trace_t *t = va_arg (*args, syn_filter4_trace_t *);
45 
46  s = format (s, "SYN_FILTER4: next index %d, %s",
47  t->next_index, t->not_a_syn ? "not a syn" : "syn");
48  if (t->not_a_syn == 0)
49  s = format (s, ", filter value %d\n", t->filter_value);
50  else
51  s = format (s, "\n");
52  return s;
53 }
54 
56 
57 #define foreach_syn_filter_error \
58 _(THROTTLED, "TCP SYN packet throttle drops") \
59 _(OK, "TCP SYN packets passed")
60 
61 typedef enum
62 {
63 #define _(sym,str) SYN_FILTER_ERROR_##sym,
65 #undef _
68 
69 static char *syn_filter4_error_strings[] = {
70 #define _(sym,string) string,
72 #undef _
73 };
74 
75 typedef enum
76 {
80 
82 
84  vlib_node_runtime_t * node,
85  vlib_frame_t * frame)
86 {
87  u32 n_left_from, *from, *to_next;
88  syn_filter_next_t next_index;
89  u32 ok_syn_packets = 0;
91  u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
93  syn_filter4_runtime_t *rt = (syn_filter4_runtime_t *) node->runtime_data;
94  f64 now = vlib_time_now (vm);
95  /* Shut up spurious gcc warnings. */
96  u8 *c0 = 0, *c1 = 0, *c2 = 0, *c3 = 0;
97 
98  from = vlib_frame_vector_args (frame);
99  n_left_from = frame->n_vectors;
100  next_index = node->cached_next_index;
101 
102  if (now > rt->next_reset)
103  {
104  clib_memset (rt->syn_counts, 0, vec_len (rt->syn_counts));
105  rt->next_reset = now + rt->reset_interval;
106  }
107 
108  while (n_left_from > 0)
109  {
110  u32 n_left_to_next;
111 
112  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
113 
114  while (n_left_from >= 8 && n_left_to_next >= 4)
115  {
116  u32 bi0, bi1, bi2, bi3;
117  vlib_buffer_t *b0, *b1, *b2, *b3;
118  u32 next0, next1, next2, next3;
119  ip4_header_t *ip0, *ip1, *ip2, *ip3;
120  tcp_header_t *tcp0, *tcp1, *tcp2, *tcp3;
121  u32 not_a_syn0 = 1, not_a_syn1 = 1, not_a_syn2 = 1, not_a_syn3 = 1;
122  u64 hash0, hash1, hash2, hash3;
123 
124  /* Prefetch next iteration. */
125  {
126  vlib_buffer_t *p4, *p5, *p6, *p7;
127 
128  p4 = vlib_get_buffer (vm, from[4]);
129  p5 = vlib_get_buffer (vm, from[5]);
130  p6 = vlib_get_buffer (vm, from[6]);
131  p7 = vlib_get_buffer (vm, from[7]);
132 
133  vlib_prefetch_buffer_header (p4, LOAD);
134  vlib_prefetch_buffer_header (p5, LOAD);
135  vlib_prefetch_buffer_header (p6, LOAD);
136  vlib_prefetch_buffer_header (p7, LOAD);
137 
142  }
143 
144  /* speculatively enqueue b0 and b1 to the current next frame */
145  to_next[0] = bi0 = from[0];
146  to_next[1] = bi1 = from[1];
147  to_next[2] = bi2 = from[2];
148  to_next[3] = bi3 = from[3];
149  from += 4;
150  to_next += 4;
151  n_left_from -= 4;
152  n_left_to_next -= 4;
153 
154  b0 = vlib_get_buffer (vm, bi0);
155  b1 = vlib_get_buffer (vm, bi1);
156  b2 = vlib_get_buffer (vm, bi2);
157  b3 = vlib_get_buffer (vm, bi3);
158 
160  (&cm->config_main, &b0->current_config_index,
161  &next0, 0 /* sizeof (c0[0]) */ );
163  (&cm->config_main, &b1->current_config_index,
164  &next1, 0 /* sizeof (c0[0]) */ );
166  (&cm->config_main, &b2->current_config_index,
167  &next2, 0 /* sizeof (c0[0]) */ );
169  (&cm->config_main, &b3->current_config_index,
170  &next3, 0 /* sizeof (c0[0]) */ );
171 
172  /* Not TCP? */
173  ip0 = vlib_buffer_get_current (b0);
174  if (ip0->protocol != IP_PROTOCOL_TCP)
175  goto trace00;
176 
177  tcp0 = ip4_next_header (ip0);
178  /*
179  * Not a SYN?
180  * $$$$ hack: the TCP bitfield flags seem not to compile
181  * correct code.
182  */
183  if (PREDICT_TRUE (!(tcp0->flags & 0x2)))
184  goto trace00;
185 
186  not_a_syn0 = 0;
187  hash0 = clib_xxhash ((u64) ip0->src_address.as_u32);
188  c0 = &rt->syn_counts[hash0 & (_vec_len (rt->syn_counts) - 1)];
189  if (PREDICT_FALSE (*c0 >= 0x80))
190  {
191  next0 = SYN_FILTER_NEXT_DROP;
192  b0->error = node->errors[SYN_FILTER_ERROR_THROTTLED];
193  goto trace00;
194  }
195  *c0 += 1;
196  ok_syn_packets++;
197 
198  trace00:
199  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
200  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
201  {
203  vlib_add_trace (vm, node, b0, sizeof (*t));
204  t->not_a_syn = not_a_syn0;
205  t->next_index = next0;
206  t->filter_value = not_a_syn0 ? 0 : *c0;
207  }
208 
209  /* Not TCP? */
210  ip1 = vlib_buffer_get_current (b1);
211  if (ip1->protocol != IP_PROTOCOL_TCP)
212  goto trace01;
213 
214  tcp1 = ip4_next_header (ip1);
215  /*
216  * Not a SYN?
217  * $$$$ hack: the TCP bitfield flags seem not to compile
218  * correct code.
219  */
220  if (PREDICT_TRUE (!(tcp1->flags & 0x2)))
221  goto trace01;
222 
223  not_a_syn1 = 0;
224  hash1 = clib_xxhash ((u64) ip1->src_address.as_u32);
225  c1 = &rt->syn_counts[hash1 & (_vec_len (rt->syn_counts) - 1)];
226  if (PREDICT_FALSE (*c1 >= 0x80))
227  {
228  next1 = SYN_FILTER_NEXT_DROP;
229  b1->error = node->errors[SYN_FILTER_ERROR_THROTTLED];
230  goto trace01;
231  }
232  *c1 += 1;
233  ok_syn_packets++;
234 
235  trace01:
236  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
237  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
238  {
240  vlib_add_trace (vm, node, b1, sizeof (*t));
241  t->not_a_syn = not_a_syn1;
242  t->next_index = next1;
243  t->filter_value = not_a_syn1 ? 0 : *c1;
244  }
245 
246  /* Not TCP? */
247  ip2 = vlib_buffer_get_current (b2);
248  if (ip2->protocol != IP_PROTOCOL_TCP)
249  goto trace02;
250 
251  tcp2 = ip4_next_header (ip2);
252  /*
253  * Not a SYN?
254  * $$$$ hack: the TCP bitfield flags seem not to compile
255  * correct code.
256  */
257  if (PREDICT_TRUE (!(tcp2->flags & 0x2)))
258  goto trace02;
259 
260  not_a_syn2 = 0;
261  hash2 = clib_xxhash ((u64) ip2->src_address.as_u32);
262  c2 = &rt->syn_counts[hash2 & (_vec_len (rt->syn_counts) - 1)];
263  if (PREDICT_FALSE (*c2 >= 0x80))
264  {
265  next2 = SYN_FILTER_NEXT_DROP;
266  b2->error = node->errors[SYN_FILTER_ERROR_THROTTLED];
267  goto trace02;
268  }
269  *c2 += 1;
270  ok_syn_packets++;
271 
272  trace02:
273  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
274  && (b2->flags & VLIB_BUFFER_IS_TRACED)))
275  {
277  vlib_add_trace (vm, node, b2, sizeof (*t));
278  t->not_a_syn = not_a_syn2;
279  t->next_index = next2;
280  t->filter_value = not_a_syn2 ? 0 : *c2;
281  }
282 
283  /* Not TCP? */
284  ip3 = vlib_buffer_get_current (b3);
285  if (ip3->protocol != IP_PROTOCOL_TCP)
286  goto trace03;
287 
288  tcp3 = ip4_next_header (ip3);
289  /*
290  * Not a SYN?
291  * $$$$ hack: the TCP bitfield flags seem not to compile
292  * correct code.
293  */
294  if (PREDICT_TRUE (!(tcp3->flags & 0x2)))
295  goto trace03;
296 
297  not_a_syn3 = 0;
298  hash3 = clib_xxhash ((u64) ip3->src_address.as_u32);
299  c3 = &rt->syn_counts[hash3 & (_vec_len (rt->syn_counts) - 1)];
300  if (PREDICT_FALSE (*c3 >= 0x80))
301  {
302  next3 = SYN_FILTER_NEXT_DROP;
303  b3->error = node->errors[SYN_FILTER_ERROR_THROTTLED];
304  goto trace03;
305  }
306  *c3 += 1;
307  ok_syn_packets++;
308 
309  trace03:
310  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
311  && (b3->flags & VLIB_BUFFER_IS_TRACED)))
312  {
314  vlib_add_trace (vm, node, b3, sizeof (*t));
315  t->not_a_syn = not_a_syn3;
316  t->next_index = next3;
317  t->filter_value = not_a_syn3 ? 0 : *c3;
318  }
319  vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
320  to_next, n_left_to_next,
321  bi0, bi1, bi2, bi3,
322  next0, next1, next2, next3);
323  }
324 
325  while (n_left_from > 0 && n_left_to_next > 0)
326  {
327  u32 bi0;
328  vlib_buffer_t *b0;
329  u32 next0;
330  ip4_header_t *ip0;
331  tcp_header_t *tcp0;
332  u32 not_a_syn0 = 1;
333  u32 hash0;
334  u8 *c0;
335 
336  /* speculatively enqueue b0 to the current next frame */
337  bi0 = from[0];
338  to_next[0] = bi0;
339  from += 1;
340  to_next += 1;
341  n_left_from -= 1;
342  n_left_to_next -= 1;
343 
344  b0 = vlib_get_buffer (vm, bi0);
345 
347  (&cm->config_main, &b0->current_config_index,
348  &next0, 0 /* sizeof (c0[0]) */ );
349 
350  /* Not TCP? */
351  ip0 = vlib_buffer_get_current (b0);
352  if (ip0->protocol != IP_PROTOCOL_TCP)
353  goto trace0;
354 
355  tcp0 = ip4_next_header (ip0);
356  /*
357  * Not a SYN?
358  * $$$$ hack: the TCP bitfield flags seem not to compile
359  * correct code.
360  */
361  if (PREDICT_TRUE (!(tcp0->flags & 0x2)))
362  goto trace0;
363 
364  not_a_syn0 = 0;
365  hash0 = clib_xxhash ((u64) ip0->src_address.as_u32);
366  c0 = &rt->syn_counts[hash0 & (_vec_len (rt->syn_counts) - 1)];
367  if (PREDICT_FALSE (*c0 >= 0x80))
368  {
369  next0 = SYN_FILTER_NEXT_DROP;
370  b0->error = node->errors[SYN_FILTER_ERROR_THROTTLED];
371  goto trace0;
372  }
373  *c0 += 1;
374  ok_syn_packets++;
375 
376  trace0:
377 
378  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
379  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
380  {
382  vlib_add_trace (vm, node, b0, sizeof (*t));
383  t->not_a_syn = not_a_syn0;
384  t->next_index = next0;
385  t->filter_value = not_a_syn0 ? 0 : *c0;
386  }
387 
388  /* verify speculative enqueue, maybe switch current next frame */
389  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
390  to_next, n_left_to_next,
391  bi0, next0);
392  }
393 
394  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
395  }
396 
398  SYN_FILTER_ERROR_OK, ok_syn_packets);
399  return frame->n_vectors;
400 }
401 
402 /* *INDENT-OFF* */
404 {
405  .name = "syn-filter-4",
406  .vector_size = sizeof (u32),
407  .format_trace = format_syn_filter4_trace,
408  .type = VLIB_NODE_TYPE_INTERNAL,
409 
410  .runtime_data_bytes = sizeof (syn_filter4_runtime_t),
412  .error_strings = syn_filter4_error_strings,
413 
414  .n_next_nodes = SYN_FILTER_N_NEXT,
415 
416  /* edit / add dispositions here */
417  .next_nodes = {
418  [SYN_FILTER_NEXT_DROP] = "error-drop",
419  },
420 };
421 /* *INDENT-ON* */
422 
423 /* *INDENT-OFF* */
424 VNET_FEATURE_INIT (syn_filter_4, static) =
425 {
426  .arc_name = "ip4-local",
427  .node_name = "syn-filter-4",
428  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
429 };
430 /* *INDENT-ON* */
431 
432 #ifndef CLIB_MARCH_VARIANT
433 int
435 {
436  vnet_main_t *vnm = vnet_get_main ();
438  int rv = 0;
439 
440  /* Utterly wrong? */
441  if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
442  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
443 
444  /* Not a physical port? */
445  sw = vnet_get_sw_interface (vnm, sw_if_index);
447  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
448 
449  if (enable_disable)
450  {
452 
453  /* *INDENT-OFF* */
455  rt = vlib_node_get_runtime_data (this_vlib_main, syn_filter4_node.index);
456  vec_validate (rt->syn_counts, 1023);
457  /*
458  * Given perfect disperson / optimal hashing results:
459  * Allow 128k (successful) syns/sec. 1024, buckets each of which
460  * absorb 128 syns before filtering. Reset table once a second.
461  * Reality bites, lets try resetting once every 100ms.
462  */
463  rt->reset_interval = 0.1; /* reset interval in seconds */
464  });
465  /* *INDENT-ON* */
466  }
467 
468  rv = vnet_feature_enable_disable ("ip4-local", "syn-filter-4",
469  sw_if_index, enable_disable, 0, 0);
470 
471  return rv;
472 }
473 
474 static clib_error_t *
476  unformat_input_t * input,
477  vlib_cli_command_t * cmd)
478 {
479  vnet_main_t *vnm = vnet_get_main ();
480  u32 sw_if_index = ~0;
481  int enable_disable = 1;
482  int rv;
483 
485  {
486  if (unformat (input, "disable"))
487  enable_disable = 0;
488  else if (unformat (input, "%U", unformat_vnet_sw_interface,
489  vnm, &sw_if_index))
490  ;
491  else
492  break;
493  }
494 
495  if (sw_if_index == ~0)
496  return clib_error_return (0, "Please specify an interface...");
497 
498  rv = syn_filter_enable_disable (sw_if_index, enable_disable);
499 
500  switch (rv)
501  {
502  case 0:
503  break;
504 
505  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
506  return clib_error_return
507  (0, "Invalid interface, only works on physical ports");
508  break;
509 
510  case VNET_API_ERROR_UNIMPLEMENTED:
511  return clib_error_return (0,
512  "Device driver doesn't support redirection");
513  break;
514 
515  case VNET_API_ERROR_INVALID_VALUE:
516  return clib_error_return (0, "feature arc not found");
517 
518  case VNET_API_ERROR_INVALID_VALUE_2:
519  return clib_error_return (0, "feature node not found");
520 
521  default:
522  return clib_error_return (0, "syn_filter_enable_disable returned %d",
523  rv);
524  }
525  return 0;
526 }
527 
528 /* *INDENT-OFF* */
529 VLIB_CLI_COMMAND (sr_content_command, static) =
530 {
531  .path = "ip syn filter",
532  .short_help = "ip syn filter <interface-name> [disable]",
534 };
535 /* *INDENT-ON* */
536 #endif /* CLIB_MARCH_VARIANT */
537 
538 /*
539  * fd.io coding-style-patch-verification: ON
540  *
541  * Local Variables:
542  * eval: (c-set-style "gnu")
543  * End:
544  */
vnet_config_main_t config_main
Definition: feature.h:82
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
u32 sw_if_index
Definition: ipsec_gre.api:37
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
#define CLIB_UNUSED(x)
Definition: clib.h:82
ip4_address_t src_address
Definition: ip4_packet.h:170
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
vnet_interface_main_t interface_main
Definition: vnet.h:56
#define PREDICT_TRUE(x)
Definition: clib.h:112
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:255
u8 data[0]
Packet data.
Definition: buffer.h:181
#define vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, next0, next1, next2, next3)
Finish enqueueing four buffers forward in the graph.
Definition: buffer_node.h:138
static u64 clib_xxhash(u64 key)
Definition: xxhash.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
unformat_function_t unformat_vnet_sw_interface
#define VLIB_NODE_FN(node)
Definition: node.h:201
struct _tcp_header tcp_header_t
static vlib_node_registration_t syn_filter4_node
(constructor) VLIB_REGISTER_NODE (syn_filter4_node)
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
#define fm
static u8 * format_syn_filter4_trace(u8 *s, va_list *args)
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
#define clib_error_return(e, args...)
Definition: error.h:99
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:241
unsigned int u32
Definition: types.h:88
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
int syn_filter_enable_disable(u32 sw_if_index, int enable_disable)
struct _unformat_input_t unformat_input_t
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
static void * vnet_get_config_data(vnet_config_main_t *cm, u32 *config_index, u32 *next_index, u32 n_data_bytes)
Definition: config.h:122
static void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Get node runtime private data by node index.
Definition: node_funcs.h:110
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define foreach_vlib_main(body)
Definition: threads.h:235
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
vlib_main_t * vm
Definition: buffer.c:312
syn_filter_next_t
vnet_feature_arc_registration_t vnet_feat_arc_ip4_local
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:283
u32 current_config_index
Used by feature subgraph arcs to visit enabled feature nodes.
Definition: buffer.h:147
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:465
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
syn_filter_error_t
VNET_FEATURE_INIT(syn_filter_4, static)
#define VNET_FEATURES(...)
Definition: feature.h:435
#define foreach_syn_filter_error
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
struct _vlib_node_registration vlib_node_registration_t
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
VLIB buffer representation.
Definition: buffer.h:102
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:815
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
struct _vnet_feature_arc_registration vnet_feature_arc_registration_t
feature registration object
vnet_sw_interface_type_t type
Definition: interface.h:682
static char * syn_filter4_error_strings[]
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
vnet_feature_config_main_t * feature_config_mains
feature config main objects
Definition: feature.h:100
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
vnet_feature_main_t feature_main
Definition: feature.c:19
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:274
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static clib_error_t * syn_filter_enable_disable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)