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