FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
ip4_source_and_port_range_check.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 <vnet/ip/ip.h>
17 #include <vnet/dpo/load_balance.h>
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/fib/ip4_fib.h>
20 
22 
23 /**
24  * @file
25  * @brief IPv4 Source and Port Range Checking.
26  *
27  * This file contains the source code for IPv4 source and port range
28  * checking.
29  */
30 
31 
32 /**
33  * @brief The pool of range chack DPOs
34  */
36 
37 /**
38  * @brief Dynamically registered DPO type
39  */
41 
44 
45 #define foreach_ip4_source_and_port_range_check_error \
46  _(CHECK_FAIL, "ip4 source and port range check bad packets") \
47  _(CHECK_OK, "ip4 source and port range check good packets")
48 
49 typedef enum
50 {
51 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
53 #undef _
56 
58 #define _(sym,string) string,
60 #undef _
61 };
62 
63 typedef struct
64 {
72 
73 static u8 *
75 {
76  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
77  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
80 
81  if (t->bypass)
82  s = format (s, "PASS (bypass case)");
83  else
84  s = format (s, "fib %d src ip %U %s dst port %d: %s",
86  t->is_tcp ? "TCP" : "UDP", (u32) t->port,
87  (t->pass == 1) ? "PASS" : "FAIL");
88  return s;
89 }
90 
91 typedef enum
92 {
96 
97 
98 static inline u32
100  u16 dst_port, u32 next)
101 {
102  u16x8vec_t key;
103  u16x8vec_t diff1;
104  u16x8vec_t diff2;
105  u16x8vec_t sum, sum_equal_diff2;
106  u16 sum_nonzero, sum_equal, winner_mask;
107  int i;
108 
109  if (NULL == ppr_dpo || dst_port == 0)
111 
112  /* Make the obvious screw-case work. A variant also works w/ no MMX */
113  if (PREDICT_FALSE (dst_port == 65535))
114  {
115  int j;
116 
117  for (i = 0;
119  i++)
120  {
121  for (j = 0; j < 8; j++)
122  if (ppr_dpo->blocks[i].low.as_u16[j] == 65535)
123  return next;
124  }
126  }
127 
128  key.as_u16x8 = u16x8_splat (dst_port);
129 
130  for (i = 0; i < ppr_dpo->n_used_blocks; i++)
131  {
132  diff1.as_u16x8 =
133  u16x8_sub_saturate (ppr_dpo->blocks[i].low.as_u16x8, key.as_u16x8);
134  diff2.as_u16x8 =
135  u16x8_sub_saturate (ppr_dpo->blocks[i].hi.as_u16x8, key.as_u16x8);
136  sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
137  sum_equal_diff2.as_u16x8 =
138  u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
139  sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
140  sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
141  winner_mask = sum_nonzero & sum_equal;
142  if (winner_mask)
143  return next;
144  }
146 }
147 
150 {
151  return (pool_elt_at_index (ppr_dpo_pool, index));
152 }
153 
156  vlib_node_runtime_t * node,
157  vlib_frame_t * frame, int is_tx)
158 {
159  ip4_main_t *im = &ip4_main;
160  u32 n_left_from, *from, *to_next;
161  u32 next_index;
162  vlib_node_runtime_t *error_node = node;
163  u32 good_packets = 0;
164  int i;
165 
166  from = vlib_frame_vector_args (frame);
167  n_left_from = frame->n_vectors;
168  next_index = node->cached_next_index;
169 
170  while (n_left_from > 0)
171  {
172  u32 n_left_to_next;
173 
174  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
175 
176 
177  /* while (n_left_from >= 4 && n_left_to_next >= 2) */
178  /* { */
179  /* vlib_buffer_t *b0, *b1; */
180  /* ip4_header_t *ip0, *ip1; */
181  /* ip4_fib_mtrie_t *mtrie0, *mtrie1; */
182  /* ip4_fib_mtrie_leaf_t leaf0, leaf1; */
183  /* ip_source_and_port_range_check_config_t *c0, *c1; */
184  /* ip_adjacency_t *adj0 = 0, *adj1 = 0; */
185  /* u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0; */
186  /* u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1; */
187  /* udp_header_t *udp0, *udp1; */
188 
189  /* /\* Prefetch next iteration. *\/ */
190  /* { */
191  /* vlib_buffer_t *p2, *p3; */
192 
193  /* p2 = vlib_get_buffer (vm, from[2]); */
194  /* p3 = vlib_get_buffer (vm, from[3]); */
195 
196  /* vlib_prefetch_buffer_header (p2, LOAD); */
197  /* vlib_prefetch_buffer_header (p3, LOAD); */
198 
199  /* CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD); */
200  /* CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD); */
201  /* } */
202 
203  /* bi0 = to_next[0] = from[0]; */
204  /* bi1 = to_next[1] = from[1]; */
205  /* from += 2; */
206  /* to_next += 2; */
207  /* n_left_from -= 2; */
208  /* n_left_to_next -= 2; */
209 
210  /* b0 = vlib_get_buffer (vm, bi0); */
211  /* b1 = vlib_get_buffer (vm, bi1); */
212 
213  /* fib_index0 = */
214  /* vec_elt (im->fib_index_by_sw_if_index, */
215  /* vnet_buffer (b0)->sw_if_index[VLIB_RX]); */
216  /* fib_index1 = */
217  /* vec_elt (im->fib_index_by_sw_if_index, */
218  /* vnet_buffer (b1)->sw_if_index[VLIB_RX]); */
219 
220  /* ip0 = vlib_buffer_get_current (b0); */
221  /* ip1 = vlib_buffer_get_current (b1); */
222 
223  /* if (is_tx) */
224  /* { */
225  /* c0 = vnet_get_config_data (&tx_cm->config_main, */
226  /* &b0->current_config_index, */
227  /* &next0, sizeof (c0[0])); */
228  /* c1 = vnet_get_config_data (&tx_cm->config_main, */
229  /* &b1->current_config_index, */
230  /* &next1, sizeof (c1[0])); */
231  /* } */
232  /* else */
233  /* { */
234  /* c0 = vnet_get_config_data (&rx_cm->config_main, */
235  /* &b0->current_config_index, */
236  /* &next0, sizeof (c0[0])); */
237  /* c1 = vnet_get_config_data (&rx_cm->config_main, */
238  /* &b1->current_config_index, */
239  /* &next1, sizeof (c1[0])); */
240  /* } */
241 
242  /* /\* we can't use the default VRF here... *\/ */
243  /* for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++) */
244  /* { */
245  /* ASSERT (c0->fib_index[i] && c1->fib_index[i]); */
246  /* } */
247 
248 
249  /* if (is_tx) */
250  /* { */
251  /* if (ip0->protocol == IP_PROTOCOL_UDP) */
252  /* fib_index0 = */
253  /* c0->fib_index */
254  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]; */
255  /* if (ip0->protocol == IP_PROTOCOL_TCP) */
256  /* fib_index0 = */
257  /* c0->fib_index */
258  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]; */
259  /* } */
260  /* else */
261  /* { */
262  /* if (ip0->protocol == IP_PROTOCOL_UDP) */
263  /* fib_index0 = */
264  /* c0->fib_index */
265  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]; */
266  /* if (ip0->protocol == IP_PROTOCOL_TCP) */
267  /* fib_index0 = */
268  /* c0->fib_index */
269  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]; */
270  /* } */
271 
272  /* if (PREDICT_TRUE (fib_index0 != ~0)) */
273  /* { */
274 
275  /* mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie; */
276 
277  /* leaf0 = IP4_FIB_MTRIE_LEAF_ROOT; */
278 
279  /* leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, */
280  /* &ip0->src_address, 0); */
281 
282  /* leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, */
283  /* &ip0->src_address, 1); */
284 
285  /* leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, */
286  /* &ip0->src_address, 2); */
287 
288  /* leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, */
289  /* &ip0->src_address, 3); */
290 
291  /* adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0); */
292 
293  /* ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0, */
294  /* &ip0->src_address, */
295  /* 0 */
296  /* /\* use dflt rt *\/ */
297  /* )); */
298  /* adj0 = ip_get_adjacency (lm, adj_index0); */
299  /* } */
300 
301  /* if (is_tx) */
302  /* { */
303  /* if (ip1->protocol == IP_PROTOCOL_UDP) */
304  /* fib_index1 = */
305  /* c1->fib_index */
306  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]; */
307  /* if (ip1->protocol == IP_PROTOCOL_TCP) */
308  /* fib_index1 = */
309  /* c1->fib_index */
310  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]; */
311  /* } */
312  /* else */
313  /* { */
314  /* if (ip1->protocol == IP_PROTOCOL_UDP) */
315  /* fib_index1 = */
316  /* c1->fib_index */
317  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]; */
318  /* if (ip1->protocol == IP_PROTOCOL_TCP) */
319  /* fib_index1 = */
320  /* c1->fib_index */
321  /* [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]; */
322  /* } */
323 
324  /* if (PREDICT_TRUE (fib_index1 != ~0)) */
325  /* { */
326 
327  /* mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie; */
328 
329  /* leaf1 = IP4_FIB_MTRIE_LEAF_ROOT; */
330 
331  /* leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, */
332  /* &ip1->src_address, 0); */
333 
334  /* leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, */
335  /* &ip1->src_address, 1); */
336 
337  /* leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, */
338  /* &ip1->src_address, 2); */
339 
340  /* leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, */
341  /* &ip1->src_address, 3); */
342 
343  /* adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1); */
344 
345  /* ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1, */
346  /* &ip1->src_address, */
347  /* 0)); */
348  /* adj1 = ip_get_adjacency (lm, adj_index1); */
349  /* } */
350 
351  /* pass0 = 0; */
352  /* pass0 |= adj0 == 0; */
353  /* pass0 |= ip4_address_is_multicast (&ip0->src_address); */
354  /* pass0 |= */
355  /* ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF); */
356  /* pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) */
357  /* && (ip0->protocol != IP_PROTOCOL_TCP); */
358 
359  /* pass1 = 0; */
360  /* pass1 |= adj1 == 0; */
361  /* pass1 |= ip4_address_is_multicast (&ip1->src_address); */
362  /* pass1 |= */
363  /* ip1->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF); */
364  /* pass1 |= (ip1->protocol != IP_PROTOCOL_UDP) */
365  /* && (ip1->protocol != IP_PROTOCOL_TCP); */
366 
367  /* save_next0 = next0; */
368  /* udp0 = ip4_next_header (ip0); */
369  /* save_next1 = next1; */
370  /* udp1 = ip4_next_header (ip1); */
371 
372  /* if (PREDICT_TRUE (pass0 == 0)) */
373  /* { */
374  /* good_packets++; */
375  /* next0 = check_adj_port_range_x1 */
376  /* (adj0, clib_net_to_host_u16 (udp0->dst_port), next0); */
377  /* good_packets -= (save_next0 != next0); */
378  /* b0->error = error_node->errors */
379  /* [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL]; */
380  /* } */
381 
382  /* if (PREDICT_TRUE (pass1 == 0)) */
383  /* { */
384  /* good_packets++; */
385  /* next1 = check_adj_port_range_x1 */
386  /* (adj1, clib_net_to_host_u16 (udp1->dst_port), next1); */
387  /* good_packets -= (save_next1 != next1); */
388  /* b1->error = error_node->errors */
389  /* [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL]; */
390  /* } */
391 
392  /* if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) */
393  /* && (b0->flags & VLIB_BUFFER_IS_TRACED))) */
394  /* { */
395  /* ip4_source_and_port_range_check_trace_t *t = */
396  /* vlib_add_trace (vm, node, b0, sizeof (*t)); */
397  /* t->pass = next0 == save_next0; */
398  /* t->bypass = pass0; */
399  /* t->fib_index = fib_index0; */
400  /* t->src_addr.as_u32 = ip0->src_address.as_u32; */
401  /* t->port = (pass0 == 0) ? */
402  /* clib_net_to_host_u16 (udp0->dst_port) : 0; */
403  /* t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP; */
404  /* } */
405 
406  /* if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) */
407  /* && (b1->flags & VLIB_BUFFER_IS_TRACED))) */
408  /* { */
409  /* ip4_source_and_port_range_check_trace_t *t = */
410  /* vlib_add_trace (vm, node, b1, sizeof (*t)); */
411  /* t->pass = next1 == save_next1; */
412  /* t->bypass = pass1; */
413  /* t->fib_index = fib_index1; */
414  /* t->src_addr.as_u32 = ip1->src_address.as_u32; */
415  /* t->port = (pass1 == 0) ? */
416  /* clib_net_to_host_u16 (udp1->dst_port) : 0; */
417  /* t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP; */
418  /* } */
419 
420  /* vlib_validate_buffer_enqueue_x2 (vm, node, next_index, */
421  /* to_next, n_left_to_next, */
422  /* bi0, bi1, next0, next1); */
423  /* } */
424 
425  while (n_left_from > 0 && n_left_to_next > 0)
426  {
427  vlib_buffer_t *b0;
428  ip4_header_t *ip0;
430  u32 bi0, next0, lb_index0, pass0, save_next0, fib_index0;
431  udp_header_t *udp0;
432  const protocol_port_range_dpo_t *ppr_dpo0 = NULL;
433  const dpo_id_t *dpo;
434  u32 sw_if_index0;
435 
436  bi0 = from[0];
437  to_next[0] = bi0;
438  from += 1;
439  to_next += 1;
440  n_left_from -= 1;
441  n_left_to_next -= 1;
442 
443  b0 = vlib_get_buffer (vm, bi0);
444  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
445 
446  fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
447 
448  if (is_tx)
449  vlib_buffer_advance (b0, sizeof (ethernet_header_t));
450 
451  ip0 = vlib_buffer_get_current (b0);
452 
453  c0 = vnet_feature_next_with_data (sw_if_index0, &next0,
454  b0, sizeof (c0[0]));
455 
456  /* we can't use the default VRF here... */
457  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
458  {
459  ASSERT (c0->fib_index[i]);
460  }
461 
462 
463  if (is_tx)
464  {
465  if (ip0->protocol == IP_PROTOCOL_UDP)
466  fib_index0 =
467  c0->fib_index
469  if (ip0->protocol == IP_PROTOCOL_TCP)
470  fib_index0 =
471  c0->fib_index
473  }
474  else
475  {
476  if (ip0->protocol == IP_PROTOCOL_UDP)
477  fib_index0 =
478  c0->fib_index
480  if (ip0->protocol == IP_PROTOCOL_TCP)
481  fib_index0 =
482  c0->fib_index
484  }
485 
486  if (fib_index0 != ~0)
487  {
488  lb_index0 = ip4_fib_forwarding_lookup (fib_index0,
489  &ip0->src_address);
490 
491  dpo =
493 
494  if (ppr_dpo_type == dpo->dpoi_type)
495  {
496  ppr_dpo0 = protocol_port_range_dpo_get (dpo->dpoi_index);
497  }
498  /*
499  * else the lookup hit an enty that was no inserted
500  * by this range checker, which is the default route
501  */
502  }
503  /*
504  * $$$ which (src,dst) categories should we always pass?
505  */
506  pass0 = 0;
507  pass0 |= ip4_address_is_multicast (&ip0->src_address);
508  pass0 |=
509  ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
510  pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
511  && (ip0->protocol != IP_PROTOCOL_TCP);
512 
513  save_next0 = next0;
514  udp0 = ip4_next_header (ip0);
515 
516  if (PREDICT_TRUE (pass0 == 0))
517  {
518  good_packets++;
520  (ppr_dpo0, clib_net_to_host_u16 (udp0->dst_port), next0);
521  good_packets -= (save_next0 != next0);
522  b0->error = error_node->errors
523  [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
524  }
525 
527  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
528  {
530  vlib_add_trace (vm, node, b0, sizeof (*t));
531  t->pass = next0 == save_next0;
532  t->bypass = pass0;
533  t->fib_index = fib_index0;
534  t->src_addr.as_u32 = ip0->src_address.as_u32;
535  t->port = (pass0 == 0) ?
536  clib_net_to_host_u16 (udp0->dst_port) : 0;
537  t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
538  }
539 
540  if (is_tx)
541  vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
542 
543  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
544  to_next, n_left_to_next,
545  bi0, next0);
546  }
547 
548  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
549  }
550 
551  if (is_tx)
553  IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
554  good_packets);
555  else
557  IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
558  good_packets);
559  return frame->n_vectors;
560 }
561 
562 static uword
564  vlib_node_runtime_t * node,
565  vlib_frame_t * frame)
566 {
567  return ip4_source_and_port_range_check_inline (vm, node, frame,
568  0 /* !is_tx */ );
569 }
570 
571 static uword
573  vlib_node_runtime_t * node,
574  vlib_frame_t * frame)
575 {
576  return ip4_source_and_port_range_check_inline (vm, node, frame,
577  1 /* is_tx */ );
578 }
579 
580 /* Note: Calling same function for both RX and TX nodes
581  as always checking dst_port, although
582  if this changes can easily make new function
583 */
584 
585 /* *INDENT-OFF* */
588  .name = "ip4-source-and-port-range-check-rx",
589  .vector_size = sizeof (u32),
590 
593 
595  .next_nodes = {
597  },
598 
599  .format_buffer = format_ip4_header,
601 };
602 /* *INDENT-ON* */
603 
604 /* *INDENT-OFF* */
607  .name = "ip4-source-and-port-range-check-tx",
608  .vector_size = sizeof (u32),
609 
612 
614  .next_nodes = {
616  },
617 
618  .format_buffer = format_ip4_header,
620 };
621 /* *INDENT-ON* */
622 
623 int
625  u32 * fib_index,
626  u32 sw_if_index, u32 is_add)
627 {
629  int rv = 0;
630  int i;
631 
632  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
633  {
634  config.fib_index[i] = fib_index[i];
635  }
636 
637  /* For OUT we are in the RX path */
638  if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] != ~0) ||
640  {
641  vnet_feature_enable_disable ("ip4-unicast",
642  "ip4-source-and-port-range-check-rx",
643  sw_if_index, is_add, &config,
644  sizeof (config));
645  }
646 
647  /* For IN we are in the TX path */
648  if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] != ~0) ||
650  {
651  vnet_feature_enable_disable ("ip4-output",
652  "ip4-source-and-port-range-check-tx",
653  sw_if_index, is_add, &config,
654  sizeof (config));
655  }
656  return rv;
657 }
658 
659 static clib_error_t *
661  unformat_input_t * input,
662  vlib_cli_command_t * cmd)
663 {
664  vnet_main_t *vnm = vnet_get_main ();
665  ip4_main_t *im = &ip4_main;
666  clib_error_t *error = 0;
667  u8 is_add = 1;
668  u32 sw_if_index = ~0;
671  int vrf_set = 0;
672  uword *p;
673  int rv = 0;
674  int i;
675 
676  sw_if_index = ~0;
677  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
678  {
679  fib_index[i] = ~0;
680  vrf_id[i] = ~0;
681  }
682 
684  {
685  if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
686  &sw_if_index))
687  ;
688  else
689  if (unformat
690  (input, "tcp-out-vrf %d",
692  vrf_set = 1;
693  else
694  if (unformat
695  (input, "udp-out-vrf %d",
697  vrf_set = 1;
698  else
699  if (unformat
700  (input, "tcp-in-vrf %d",
702  vrf_set = 1;
703  else
704  if (unformat
705  (input, "udp-in-vrf %d",
707  vrf_set = 1;
708  else if (unformat (input, "del"))
709  is_add = 0;
710  else
711  break;
712  }
713 
714  if (sw_if_index == ~0)
715  return clib_error_return (0, "Interface required but not specified");
716 
717  if (!vrf_set)
718  return clib_error_return (0,
719  "TCP or UDP VRF ID required but not specified");
720 
721  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
722  {
723 
724  if (vrf_id[i] == 0)
725  return clib_error_return (0,
726  "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
727 
728  if (vrf_id[i] != ~0)
729  {
730  p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
731 
732  if (p == 0)
733  return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
734 
735  fib_index[i] = p[0];
736  }
737  }
738  rv =
739  set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
740 
741  switch (rv)
742  {
743  case 0:
744  break;
745 
746  default:
747  return clib_error_return
748  (0,
749  "set source and port-range on interface returned an unexpected value: %d",
750  rv);
751  }
752  return error;
753 }
754 
755 /*?
756  * Add the 'ip4-source-and-port-range-check-rx' or
757  * 'ip4-source-and-port-range-check-tx' graph node for a given
758  * interface. 'tcp-out-vrf' and 'udp-out-vrf' will add to
759  * the RX path. 'tcp-in-vrf' and 'udp-in-vrf' will add to
760  * the TX path. A graph node will be inserted into the chain when
761  * the range check is added to the first interface. It will not
762  * be removed from when range check is removed from the last
763  * interface.
764  *
765  * By adding the range check graph node to the interface, incoming
766  * or outgoing TCP/UDP packets will be validated using the
767  * provided IPv4 FIB table (VRF).
768  *
769  * @note 'ip4-source-and-port-range-check-rx' and
770  * 'ip4-source-and-port-range-check-tx' strings are too long, so
771  * they are truncated on the 'show vlib graph' output.
772  *
773  * @todo This content needs to be validated and potentially more detail added.
774  *
775  * @cliexpar
776  * @parblock
777  * Example of graph node before range checking is enabled:
778  * @cliexstart{show vlib graph ip4-source-and-port-range-check-tx}
779  * Name Next Previous
780  * ip4-source-and-port-range- ip4-drop [0]
781  * @cliexend
782  *
783  * Example of how to enable range checking on TX:
784  * @cliexcmd{set interface ip source-and-port-range-check GigabitEthernet2/0/0 udp-in-vrf 7}
785  *
786  * Example of graph node after range checking is enabled:
787  * @cliexstart{show vlib graph ip4-source-and-port-range-check-tx}
788  * Name Next Previous
789  * ip4-source-and-port-range- ip4-drop [0] ip4-rewrite
790  * interface-output [1]
791  * @cliexend
792  *
793  * Example of how to display the features enabed on an interface:
794  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
795  * IP feature paths configured on GigabitEthernet2/0/0...
796  *
797  * ipv4 unicast:
798  * ip4-source-and-port-range-check-rx
799  * ip4-lookup
800  *
801  * ipv4 multicast:
802  * ip4-lookup-multicast
803  *
804  * ipv4 multicast:
805  * interface-output
806  *
807  * ipv6 unicast:
808  * ip6-lookup
809  *
810  * ipv6 multicast:
811  * ip6-lookup
812  *
813  * ipv6 multicast:
814  * interface-output
815  * @cliexend
816  * @endparblock
817 ?*/
818 /* *INDENT-OFF* */
819 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command, static) = {
820  .path = "set interface ip source-and-port-range-check",
822  .short_help = "set interface ip source-and-port-range-check <interface> [tcp-out-vrf <table-id>] [udp-out-vrf <table-id>] [tcp-in-vrf <table-id>] [udp-in-vrf <table-id>] [del]",
823 };
824 /* *INDENT-ON* */
825 
826 static u8 *
827 format_ppr_dpo (u8 * s, va_list * args)
828 {
829  index_t index = va_arg (*args, index_t);
830  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
831 
832  protocol_port_range_dpo_t *ppr_dpo;
833  int i, j;
834  int printed = 0;
835 
836  ppr_dpo = protocol_port_range_dpo_get (index);
837 
838  s = format (s, "allow ");
839 
840  for (i = 0; i < ppr_dpo->n_used_blocks; i++)
841  {
842  for (j = 0; j < 8; j++)
843  {
844  if (ppr_dpo->blocks[i].low.as_u16[j])
845  {
846  if (printed)
847  s = format (s, ", ");
848  if (ppr_dpo->blocks[i].hi.as_u16[j] >
849  (ppr_dpo->blocks[i].low.as_u16[j] + 1))
850  s =
851  format (s, "%d-%d", (u32) ppr_dpo->blocks[i].low.as_u16[j],
852  (u32) ppr_dpo->blocks[i].hi.as_u16[j] - 1);
853  else
854  s = format (s, "%d", ppr_dpo->blocks[i].low.as_u16[j]);
855  printed = 1;
856  }
857  }
858  }
859  return s;
860 }
861 
862 static void
864 {
865 }
866 
867 static void
869 {
870 }
871 
872 const static dpo_vft_t ppr_vft = {
874  .dv_unlock = ppr_dpo_unlock,
875  .dv_format = format_ppr_dpo,
876 };
877 
878 const static char *const ppr_ip4_nodes[] = {
879  "ip4-source-and-port-range-check-rx",
880  NULL,
881 };
882 
883 const static char *const *const ppr_nodes[DPO_PROTO_NUM] = {
885 };
886 
887 clib_error_t *
889 {
891 
892  srm->vlib_main = vm;
893  srm->vnet_main = vnet_get_main ();
894 
896 
897  return 0;
898 }
899 
901 
904 {
905  protocol_port_range_dpo_t *ppr_dpo;
906 
907  pool_get_aligned (ppr_dpo_pool, ppr_dpo, CLIB_CACHE_LINE_BYTES);
908  memset (ppr_dpo, 0, sizeof (*ppr_dpo));
909 
911 
912  return (ppr_dpo);
913 }
914 
915 
916 static int
918  ip4_address_t * address,
919  u32 length, u16 * low_ports, u16 * high_ports)
920 {
921  protocol_port_range_dpo_t *ppr_dpo;
922  dpo_id_t dpop = DPO_INVALID;
923  int i, j, k;
924 
925  fib_node_index_t fei;
926  fib_prefix_t pfx = {
928  .fp_len = length,
929  .fp_addr = {
930  .ip4 = *address,
931  },
932  };
933 
934  /*
935  * check to see if we have already sourced this prefix
936  */
937  fei = fib_table_lookup_exact_match (fib_index, &pfx);
938 
939  if (FIB_NODE_INDEX_INVALID == fei)
940  {
941  /*
942  * this is a first time add for this prefix.
943  */
944  ppr_dpo = protocol_port_range_dpo_alloc ();
945  }
946  else
947  {
948  /*
949  * the prefix is already there.
950  * check it was sourced by us, and if so get the ragne DPO from it.
951  */
952  dpo_id_t dpo = DPO_INVALID;
953  const dpo_id_t *bucket;
954 
956  {
957  /*
958  * there is existing state. we'll want to add the new ranges to it
959  */
960  bucket =
962  ppr_dpo = protocol_port_range_dpo_get (bucket->dpoi_index);
963  dpo_reset (&dpo);
964  }
965  else
966  {
967  /*
968  * there is no PPR state associated with this prefix,
969  * so we'll need a new DPO
970  */
971  ppr_dpo = protocol_port_range_dpo_alloc ();
972  }
973  }
974 
975  if (vec_len (low_ports) > ppr_dpo->n_free_ranges)
976  return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
977 
978  j = k = 0;
979 
980  for (i = 0; i < vec_len (low_ports); i++)
981  {
982  for (; j < N_BLOCKS_PER_DPO; j++)
983  {
984  for (; k < 8; k++)
985  {
986  if (ppr_dpo->blocks[j].low.as_u16[k] == 0)
987  {
988  ppr_dpo->blocks[j].low.as_u16[k] = low_ports[i];
989  ppr_dpo->blocks[j].hi.as_u16[k] = high_ports[i];
990  goto doublebreak;
991  }
992  }
993  }
994  doublebreak:;
995  }
996  ppr_dpo->n_used_blocks = j + 1;
997 
998  /*
999  * add or update the entry in the FIB
1000  */
1001  dpo_set (&dpop, ppr_dpo_type, DPO_PROTO_IP4, (ppr_dpo - ppr_dpo_pool));
1002 
1003  if (FIB_NODE_INDEX_INVALID == fei)
1004  {
1006  &pfx,
1008  FIB_ENTRY_FLAG_NONE, &dpop);
1009  }
1010  else
1011  {
1014  FIB_ENTRY_FLAG_NONE, &dpop);
1015  }
1016 
1017  return 0;
1018 }
1019 
1020 static int
1022  ip4_address_t * address,
1023  u32 length, u16 * low_ports, u16 * high_ports)
1024 {
1025  protocol_port_range_dpo_t *ppr_dpo;
1026  fib_node_index_t fei;
1027  int i, j, k;
1028 
1029  fib_prefix_t pfx = {
1031  .fp_len = length,
1032  .fp_addr = {
1033  .ip4 = *address,
1034  },
1035  };
1036 
1037  /*
1038  * check to see if we have sourced this prefix
1039  */
1040  fei = fib_table_lookup_exact_match (fib_index, &pfx);
1041 
1042  if (FIB_NODE_INDEX_INVALID == fei)
1043  {
1044  /*
1045  * not one of ours
1046  */
1047  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
1048  }
1049  else
1050  {
1051  /*
1052  * the prefix is already there.
1053  * check it was sourced by us
1054  */
1055  dpo_id_t dpo = DPO_INVALID;
1056  const dpo_id_t *bucket;
1057 
1059  {
1060  /*
1061  * there is existing state. we'll want to add the new ranges to it
1062  */
1063  bucket =
1065  ppr_dpo = protocol_port_range_dpo_get (bucket->dpoi_index);
1066  dpo_reset (&dpo);
1067  }
1068  else
1069  {
1070  /*
1071  * not one of ours
1072  */
1073  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
1074  }
1075  }
1076 
1077  for (i = 0; i < vec_len (low_ports); i++)
1078  {
1079  for (j = 0; j < N_BLOCKS_PER_DPO; j++)
1080  {
1081  for (k = 0; k < 8; k++)
1082  {
1083  if (low_ports[i] == ppr_dpo->blocks[j].low.as_u16[k] &&
1084  high_ports[i] == ppr_dpo->blocks[j].hi.as_u16[k])
1085  {
1086  ppr_dpo->blocks[j].low.as_u16[k] =
1087  ppr_dpo->blocks[j].hi.as_u16[k] = 0;
1088  goto doublebreak;
1089  }
1090  }
1091  }
1092  doublebreak:;
1093  }
1094 
1095  ppr_dpo->n_free_ranges = 0;
1096 
1097  /* Have we deleted all ranges yet? */
1098  for (i = 0; i < N_BLOCKS_PER_DPO; i++)
1099  {
1100  for (j = 0; j < 8; j++)
1101  {
1102  if (ppr_dpo->blocks[j].low.as_u16[i] == 0)
1103  ppr_dpo->n_free_ranges++;
1104  }
1105  }
1106 
1107  if (N_PORT_RANGES_PER_DPO == ppr_dpo->n_free_ranges)
1108  {
1109  /* Yes, lose the adjacency... */
1111  }
1112  else
1113  {
1114  /*
1115  * compact the ranges down to a contiguous block
1116  */
1117  // FIXME. TODO.
1118  }
1119 
1120  return 0;
1121 }
1122 
1123 // This will be moved to another file and implemented post API freeze.
1124 int
1126  u32 length,
1127  u32 vrf_id,
1128  u16 * low_ports,
1129  u16 * high_ports, int is_add)
1130 {
1131  u32 fib_index;
1132 
1133  fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
1134 
1135  ASSERT (~0 != fib_index);
1136 
1138 
1139  return 0;
1140 }
1141 
1142 int
1144  u32 length,
1145  u32 vrf_id,
1146  u16 * low_ports,
1147  u16 * high_ports, int is_add)
1148 {
1149  u32 fib_index;
1150 
1153 
1154  if (is_add == 0)
1155  {
1156  remove_port_range_adjacency (fib_index, address, length,
1157  low_ports, high_ports);
1158  }
1159  else
1160  {
1161  add_port_range_adjacency (fib_index, address, length,
1162  low_ports, high_ports);
1163  }
1164 
1165  return 0;
1166 }
1167 
1168 static clib_error_t *
1170  unformat_input_t * input,
1171  vlib_cli_command_t * cmd)
1172 {
1173  u16 *low_ports = 0;
1174  u16 *high_ports = 0;
1175  u16 this_low;
1176  u16 this_hi;
1177  ip4_address_t ip4_addr;
1178  ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
1179  u32 length;
1180  u32 tmp, tmp2;
1181  u32 vrf_id = ~0;
1182  int is_add = 1, ip_ver = ~0;
1183  int rv;
1184 
1185 
1186  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1187  {
1188  if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
1189  ip_ver = 4;
1190  else
1191  if (unformat
1192  (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
1193  ip_ver = 6;
1194  else if (unformat (input, "vrf %d", &vrf_id))
1195  ;
1196  else if (unformat (input, "del"))
1197  is_add = 0;
1198  else if (unformat (input, "port %d", &tmp))
1199  {
1200  if (tmp == 0 || tmp > 65535)
1201  return clib_error_return (0, "port %d out of range", tmp);
1202  this_low = tmp;
1203  this_hi = this_low + 1;
1204  vec_add1 (low_ports, this_low);
1205  vec_add1 (high_ports, this_hi);
1206  }
1207  else if (unformat (input, "range %d - %d", &tmp, &tmp2))
1208  {
1209  if (tmp > tmp2)
1210  return clib_error_return (0, "ports %d and %d out of order",
1211  tmp, tmp2);
1212  if (tmp == 0 || tmp > 65535)
1213  return clib_error_return (0, "low port %d out of range", tmp);
1214  if (tmp2 == 0 || tmp2 > 65535)
1215  return clib_error_return (0, "high port %d out of range", tmp2);
1216  this_low = tmp;
1217  this_hi = tmp2 + 1;
1218  vec_add1 (low_ports, this_low);
1219  vec_add1 (high_ports, this_hi);
1220  }
1221  else
1222  break;
1223  }
1224 
1225  if (ip_ver == ~0)
1226  return clib_error_return (0, " <address>/<mask> not specified");
1227 
1228  if (vrf_id == ~0)
1229  return clib_error_return (0, " VRF ID required, not specified");
1230 
1231  if (vec_len (low_ports) == 0)
1232  return clib_error_return (0,
1233  " Both VRF ID and range/port must be set for a protocol.");
1234 
1235  if (vrf_id == 0)
1236  return clib_error_return (0, " VRF ID can not be 0 (default).");
1237 
1238 
1239  if (ip_ver == 4)
1241  (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
1242  else
1243  return clib_error_return (0, " IPv6 in subsequent patch");
1244 
1245  switch (rv)
1246  {
1247  case 0:
1248  break;
1249 
1250  case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
1251  return clib_error_return
1252  (0, " Incorrect adjacency for add/del operation");
1253 
1254  case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
1255  return clib_error_return (0, " Too many ports in add/del operation");
1256 
1257  case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
1258  return clib_error_return
1259  (0, " Too many ranges requested for add operation");
1260 
1261  default:
1262  return clib_error_return (0, " returned an unexpected value: %d", rv);
1263  }
1264 
1265  return 0;
1266 }
1267 
1268 /*?
1269  * This command adds an IP Subnet and range of ports to be validated
1270  * by an IP FIB table (VRF).
1271  *
1272  * @todo This is incomplete. This needs a detailed description and a
1273  * practical example.
1274  *
1275  * @cliexpar
1276  * Example of how to add an IPv4 subnet and single port to an IPv4 FIB table:
1277  * @cliexcmd{set ip source-and-port-range-check vrf 7 172.16.1.0/24 port 23}
1278  * Example of how to add an IPv4 subnet and range of ports to an IPv4 FIB table:
1279  * @cliexcmd{set ip source-and-port-range-check vrf 7 172.16.1.0/24 range 23 - 100}
1280  * Example of how to delete an IPv4 subnet and single port from an IPv4 FIB table:
1281  * @cliexcmd{set ip source-and-port-range-check vrf 7 172.16.1.0/24 port 23 del}
1282  * Example of how to delete an IPv4 subnet and range of ports from an IPv4 FIB table:
1283  * @cliexcmd{set ip source-and-port-range-check vrf 7 172.16.1.0/24 range 23 - 100 del}
1284 ?*/
1285 /* *INDENT-OFF* */
1286 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
1287  .path = "set ip source-and-port-range-check",
1289  .short_help =
1290  "set ip source-and-port-range-check vrf <table-id> <ip-addr>/<mask> {port nn | range <nn> - <nn>} [del]",
1291 };
1292 /* *INDENT-ON* */
1293 
1294 
1295 static clib_error_t *
1297  unformat_input_t * input,
1298  vlib_cli_command_t * cmd)
1299 {
1300  protocol_port_range_dpo_t *ppr_dpo;
1301  u32 fib_index;
1302  u8 addr_set = 0;
1303  u32 vrf_id = ~0;
1304  int rv, i, j;
1305  u32 port = 0;
1306  fib_prefix_t pfx = {
1308  .fp_len = 32,
1309  };
1310 
1311  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1312  {
1313  if (unformat (input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
1314  addr_set = 1;
1315  else if (unformat (input, "vrf %d", &vrf_id))
1316  ;
1317  else if (unformat (input, "port %d", &port))
1318  ;
1319  else
1320  break;
1321  }
1322 
1323  if (addr_set == 0)
1324  return clib_error_return (0, "<address> not specified");
1325 
1326  if (vrf_id == ~0)
1327  return clib_error_return (0, "VRF ID required, not specified");
1328 
1329  fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
1330  if (~0 == fib_index)
1331  return clib_error_return (0, "VRF %d not found", vrf_id);
1332 
1333  /*
1334  * find the longest prefix match on the address requested,
1335  * check it was sourced by us
1336  */
1337  dpo_id_t dpo = DPO_INVALID;
1338  const dpo_id_t *bucket;
1339 
1340  if (!fib_entry_get_dpo_for_source (fib_table_lookup (fib_index, &pfx),
1341  FIB_SOURCE_SPECIAL, &dpo))
1342  {
1343  /*
1344  * not one of ours
1345  */
1346  vlib_cli_output (vm, "%U: src address drop", format_ip4_address,
1347  &pfx.fp_addr.ip4);
1348  return 0;
1349  }
1350 
1352  ppr_dpo = protocol_port_range_dpo_get (bucket->dpoi_index);
1353  dpo_reset (&dpo);
1354 
1355  if (port)
1356  {
1357  rv = check_adj_port_range_x1 (ppr_dpo, (u16) port, 1234);
1358  if (rv == 1234)
1359  vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
1360  &pfx.fp_addr.ip4, port);
1361  else
1362  vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
1363  &pfx.fp_addr.ip4, port);
1364  return 0;
1365  }
1366  else
1367  {
1368  u8 *s;
1369 
1370  s = format (0, "%U: ", format_ip4_address, &pfx.fp_addr.ip4);
1371 
1372  for (i = 0; i < N_BLOCKS_PER_DPO; i++)
1373  {
1374  for (j = 0; j < 8; j++)
1375  {
1376  if (ppr_dpo->blocks[i].low.as_u16[j])
1377  s = format (s, "%d - %d ",
1378  (u32) ppr_dpo->blocks[i].low.as_u16[j],
1379  (u32) ppr_dpo->blocks[i].hi.as_u16[j]);
1380  }
1381  }
1382  vlib_cli_output (vm, "%s", s);
1383  vec_free (s);
1384  }
1385 
1386  return 0;
1387 }
1388 
1389 /*?
1390  * Display the range of ports being validated by an IPv4 FIB for a given
1391  * IP or subnet, or test if a given IP and port are being validated.
1392  *
1393  * @todo This is incomplete. This needs a detailed description and a
1394  * practical example.
1395  *
1396  * @cliexpar
1397  * Example of how to display the set of ports being validated for a given
1398  * IPv4 subnet:
1399  * @cliexstart{show ip source-and-port-range-check vrf 7 172.16.2.0}
1400  * 172.16.2.0: 23 - 101
1401  * @cliexend
1402  * Example of how to test to determine of a given Pv4 address and port
1403  * are being validated:
1404  * @cliexstart{show ip source-and-port-range-check vrf 7 172.16.2.2 port 23}
1405  * 172.16.2.2 port 23 PASS
1406  * @cliexend
1407  * @cliexstart{show ip source-and-port-range-check vrf 7 172.16.2.2 port 250}
1408  * 172.16.2.2 port 250 FAIL
1409  * @cliexend
1410  ?*/
1411 /* *INDENT-OFF* */
1412 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
1413  .path = "show ip source-and-port-range-check",
1415  .short_help =
1416  "show ip source-and-port-range-check vrf <table-id> <ip-addr> [port <n>]",
1417 };
1418 /* *INDENT-ON* */
1419 
1420 /*
1421  * fd.io coding-style-patch-verification: ON
1422  *
1423  * Local Variables:
1424  * eval: (c-set-style "gnu")
1425  * End:
1426  */
static clib_error_t * ip_source_and_port_range_check_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:197
static u8 * format_ip4_source_and_port_range_check_trace(u8 *s, va_list *va)
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:404
static u8 * format_ppr_dpo(u8 *s, va_list *args)
ip4_source_and_port_range_check_error_t
#define CLIB_UNUSED(x)
Definition: clib.h:79
A virtual function table regisitered for a DPO type.
Definition: dpo.h:399
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
ip4_address_t src_address
Definition: ip4_packet.h:164
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
format_function_t format_ip4_header
Definition: format.h:86
#define PREDICT_TRUE(x)
Definition: clib.h:106
vlib_node_registration_t ip4_source_port_and_range_check_rx
(constructor) VLIB_REGISTER_NODE (ip4_source_port_and_range_check_rx)
#define NULL
Definition: clib.h:55
#define foreach_ip4_source_and_port_range_check_error
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:52
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
static uword ip4_source_and_port_range_check_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_tx)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:520
int i
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:111
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
static const char *const ppr_ip4_nodes[]
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
static void ppr_dpo_lock(dpo_id_t *dpo)
format_function_t format_ip4_address
Definition: format.h:79
void fib_entry_special_update(fib_node_index_t fib_entry_index, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Definition: fib_entry.c:856
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
unformat_function_t unformat_ip4_address
Definition: format.h:76
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:399
#define always_inline
Definition: clib.h:92
vlib_node_registration_t ip4_source_port_and_range_check_tx
(constructor) VLIB_REGISTER_NODE (ip4_source_port_and_range_check_tx)
Aggregrate type for a prefix.
Definition: fib_types.h:188
protocol_port_range_dpo_t * protocol_port_range_dpo_alloc(void)
#define clib_error_return(e, args...)
Definition: error.h:99
static u32 check_adj_port_range_x1(const protocol_port_range_dpo_t *ppr_dpo, u16 dst_port, u32 next)
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:233
static clib_error_t * set_ip_source_and_port_range_check_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1037
ip4_source_and_port_range_check_next_t
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:66
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:341
Definition: fib_entry.h:270
const int fib_entry_get_dpo_for_source(fib_node_index_t fib_entry_index, fib_source_t source, dpo_id_t *dpo)
static u32 u16x8_zero_byte_mask(u16x8 input)
Definition: vector_neon.h:64
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:168
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:121
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:211
dpo_type_t dpoi_type
the type
Definition: dpo.h:172
static clib_error_t * show_source_and_port_range_check_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static const dpo_id_t * load_balance_get_bucket_i(const load_balance_t *lb, u32 bucket)
Definition: load_balance.h:209
struct _unformat_input_t unformat_input_t
The object that is in the data-path to perform the check.
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
static int remove_port_range_adjacency(u32 fib_index, ip4_address_t *address, u32 length, u16 *low_ports, u16 *high_ports)
u16 n_used_blocks
The number of blocks from the &#39;block&#39; array below that have rnages configured.
static uword ip4_address_is_multicast(ip4_address_t *a)
Definition: ip4_packet.h:310
#define PREDICT_FALSE(x)
Definition: clib.h:105
#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 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:364
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1209
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:130
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1166
unformat_function_t unformat_ip6_address
Definition: format.h:94
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:188
u16 n_free_ranges
The total number of free ranges from all blocks.
#define u16x8_sub_saturate(a, b)
Definition: vector_neon.h:21
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:59
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:454
#define N_BLOCKS_PER_DPO
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:185
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
protocol_port_range_t blocks[N_BLOCKS_PER_DPO]
the fixed size array of ranges
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:299
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static const char *const *const ppr_nodes[DPO_PROTO_NUM]
source_range_check_main_t source_range_check_main
static load_balance_t * load_balance_get(index_t lbi)
Definition: load_balance.h:200
IPv4 main type.
Definition: ip4.h:95
Classify.
Definition: fib_entry.h:44
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1096
static index_t ip4_fib_forwarding_lookup(u32 fib_index, const ip4_address_t *addr)
Definition: ip4_fib.h:164
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:222
#define N_PORT_RANGES_PER_DPO
The number of supported ranges per-data path object.
u64 uword
Definition: types.h:112
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:55
#define vec_elt(v, i)
Get vector value at index i.
struct _vlib_node_registration vlib_node_registration_t
unsigned short u16
Definition: types.h:57
#define DPO_PROTO_NUM
Definition: dpo.h:70
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:184
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
static int add_port_range_adjacency(u32 fib_index, ip4_address_t *address, u32 length, u16 *low_ports, u16 *high_ports)
clib_error_t * ip4_source_and_port_range_check_init(vlib_main_t *vm)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static void ppr_dpo_unlock(dpo_id_t *dpo)
static protocol_port_range_dpo_t * protocol_port_range_dpo_get(index_t index)
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:195
int ip4_source_and_port_range_check_add_del(ip4_address_t *address, u32 length, u32 vrf_id, u16 *low_ports, u16 *high_ports, int is_add)
Special sources.
Definition: fib_entry.h:40
static_always_inline void * vnet_feature_next_with_data(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0, u32 n_data_bytes)
Definition: feature.h:208
#define vnet_buffer(b)
Definition: buffer.h:372
static uword ip4_source_and_port_range_check_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:818
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:231
u16 flags
Copy of main node flags.
Definition: node.h:450
static dpo_type_t ppr_dpo_type
Dynamically registered DPO type.
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
int ip6_source_and_port_range_check_add_del(ip6_address_t *address, u32 length, u32 vrf_id, u16 *low_ports, u16 *high_ports, int is_add)
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:111
static char * ip4_source_and_port_range_check_error_strings[]
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static uword ip4_source_and_port_range_check_rx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static protocol_port_range_dpo_t * ppr_dpo_pool
The pool of range chack DPOs.
Definition: defs.h:46
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:233
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS]
int set_ip_source_and_port_range_check(vlib_main_t *vm, u32 *fib_index, u32 sw_if_index, u32 is_add)