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