FD.io VPP  v16.09
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 
18 
20 
21 #define foreach_ip4_source_and_port_range_check_error \
22  _(CHECK_FAIL, "ip4 source and port range check bad packets") \
23  _(CHECK_OK, "ip4 source and port range check good packets")
24 
25 typedef enum
26 {
27 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
29 #undef _
32 
34 #define _(sym,string) string,
36 #undef _
37 };
38 
39 typedef struct
40 {
48 
49 static u8 *
51 {
52  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
53  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
56 
57  if (t->bypass)
58  s = format (s, "PASS (bypass case)");
59  else
60  s = format (s, "fib %d src ip %U %s dst port %d: %s",
62  t->is_tcp ? "TCP" : "UDP", (u32) t->dst_port,
63  (t->pass == 1) ? "PASS" : "FAIL");
64  return s;
65 }
66 
67 typedef enum
68 {
72 
73 
74 static inline u32
76 {
77  protocol_port_range_t *range;
78  u16x8vec_t key;
79  u16x8vec_t diff1;
80  u16x8vec_t diff2;
81  u16x8vec_t sum, sum_equal_diff2;
82  u16 sum_nonzero, sum_equal, winner_mask;
83  int i;
84  u8 *rwh;
85 
86  if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR || dst_port == 0)
88 
89  rwh = (u8 *) (&adj->rewrite_header);
90  range = (protocol_port_range_t *) rwh;
91 
92  /* Make the obvious screw-case work. A variant also works w/ no MMX */
93  if (PREDICT_FALSE (dst_port == 65535))
94  {
95  int j;
96 
97  for (i = 0;
99  i++)
100  {
101  for (j = 0; j < 8; j++)
102  if (range->low.as_u16[j] == 65535)
103  return next;
104  range++;
105  }
107  }
108 
109  key.as_u16x8 = u16x8_splat (dst_port);
110 
111  for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof (protocol_port_range_t);
112  i++)
113  {
114  diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
115  diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
116  sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
117  sum_equal_diff2.as_u16x8 =
118  u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
119  sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
120  sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
121  winner_mask = sum_nonzero & sum_equal;
122  if (winner_mask)
123  return next;
124  range++;
125  }
127 }
128 
132 {
133  ip4_main_t *im = &ip4_main;
134  ip_lookup_main_t *lm = &im->lookup_main;
136  u32 n_left_from, *from, *to_next;
137  u32 next_index;
138  vlib_node_runtime_t *error_node = node;
139  u32 good_packets = 0;
140  int i;
141 
142  from = vlib_frame_vector_args (frame);
143  n_left_from = frame->n_vectors;
144  next_index = node->cached_next_index;
145 
146  while (n_left_from > 0)
147  {
148  u32 n_left_to_next;
149 
150  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
151 
152 
153  while (n_left_from >= 4 && n_left_to_next >= 2)
154  {
155  vlib_buffer_t *b0, *b1;
156  ip4_header_t *ip0, *ip1;
157  ip4_fib_mtrie_t *mtrie0, *mtrie1;
158  ip4_fib_mtrie_leaf_t leaf0, leaf1;
160  ip_adjacency_t *adj0 = 0, *adj1 = 0;
161  u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
162  u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1;
163  udp_header_t *udp0, *udp1;
164 
165  /* Prefetch next iteration. */
166  {
167  vlib_buffer_t *p2, *p3;
168 
169  p2 = vlib_get_buffer (vm, from[2]);
170  p3 = vlib_get_buffer (vm, from[3]);
171 
172  vlib_prefetch_buffer_header (p2, LOAD);
173  vlib_prefetch_buffer_header (p3, LOAD);
174 
175  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
176  CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
177  }
178 
179  bi0 = to_next[0] = from[0];
180  bi1 = to_next[1] = from[1];
181  from += 2;
182  to_next += 2;
183  n_left_from -= 2;
184  n_left_to_next -= 2;
185 
186  b0 = vlib_get_buffer (vm, bi0);
187  b1 = vlib_get_buffer (vm, bi1);
188 
189  fib_index0 =
191  vnet_buffer (b0)->sw_if_index[VLIB_RX]);
192  fib_index1 =
194  vnet_buffer (b1)->sw_if_index[VLIB_RX]);
195 
196  ip0 = vlib_buffer_get_current (b0);
197  ip1 = vlib_buffer_get_current (b1);
198 
201  &next0, sizeof (c0[0]));
204  &next1, sizeof (c1[0]));
205 
206  /* we can't use the default VRF here... */
207  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
208  {
209  ASSERT (c0->fib_index[i] && c1->fib_index[i]);
210  }
211 
212 
213  if (ip0->protocol == IP_PROTOCOL_UDP)
214  fib_index0 =
216  if (ip0->protocol == IP_PROTOCOL_TCP)
217  fib_index0 =
219 
220  if (PREDICT_TRUE (fib_index0 != ~0))
221  {
222 
223  mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
224 
225  leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
226 
227  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
228  &ip0->src_address, 0);
229 
230  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
231  &ip0->src_address, 1);
232 
233  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
234  &ip0->src_address, 2);
235 
236  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
237  &ip0->src_address, 3);
238 
239  adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
240 
241  ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
242  &ip0->
243  src_address, 0
244  /* use dflt rt */
245  ));
246  adj0 = ip_get_adjacency (lm, adj_index0);
247  }
248 
249  if (ip1->protocol == IP_PROTOCOL_UDP)
250  fib_index1 =
252  if (ip1->protocol == IP_PROTOCOL_TCP)
253  fib_index1 =
255 
256  if (PREDICT_TRUE (fib_index1 != ~0))
257  {
258 
259  mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
260 
261  leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
262 
263  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
264  &ip1->src_address, 0);
265 
266  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
267  &ip1->src_address, 1);
268 
269  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
270  &ip1->src_address, 2);
271 
272  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
273  &ip1->src_address, 3);
274 
275  adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
276 
277  ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
278  &ip1->
279  src_address,
280  0));
281  adj1 = ip_get_adjacency (lm, adj_index1);
282  }
283 
284  pass0 = 0;
285  pass0 |= adj0 == 0;
286  pass0 |= ip4_address_is_multicast (&ip0->src_address);
287  pass0 |=
288  ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
289  pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
290  && (ip0->protocol != IP_PROTOCOL_TCP);
291 
292  pass1 = 0;
293  pass1 |= adj1 == 0;
294  pass1 |= ip4_address_is_multicast (&ip1->src_address);
295  pass1 |=
296  ip1->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
297  pass1 |= (ip1->protocol != IP_PROTOCOL_UDP)
298  && (ip1->protocol != IP_PROTOCOL_TCP);
299 
300  save_next0 = next0;
301  udp0 = ip4_next_header (ip0);
302  save_next1 = next1;
303  udp1 = ip4_next_header (ip1);
304 
305  if (PREDICT_TRUE (pass0 == 0))
306  {
307  good_packets++;
309  (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
310  good_packets -= (save_next0 != next0);
311  b0->error = error_node->errors
312  [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
313  }
314 
315  if (PREDICT_TRUE (pass1 == 0))
316  {
317  good_packets++;
319  (adj1, clib_net_to_host_u16 (udp1->dst_port), next1);
320  good_packets -= (save_next1 != next1);
321  b1->error = error_node->errors
322  [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
323  }
324 
326  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
327  {
329  vlib_add_trace (vm, node, b0, sizeof (*t));
330  t->pass = next0 == save_next0;
331  t->bypass = pass0;
332  t->fib_index = fib_index0;
333  t->src_addr.as_u32 = ip0->src_address.as_u32;
334  t->dst_port = (pass0 == 0) ?
335  clib_net_to_host_u16 (udp0->dst_port) : 0;
336  t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
337  }
338 
340  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
341  {
343  vlib_add_trace (vm, node, b1, sizeof (*t));
344  t->pass = next1 == save_next1;
345  t->bypass = pass1;
346  t->fib_index = fib_index1;
347  t->src_addr.as_u32 = ip1->src_address.as_u32;
348  t->dst_port = (pass1 == 0) ?
349  clib_net_to_host_u16 (udp1->dst_port) : 0;
350  t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
351  }
352 
353  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
354  to_next, n_left_to_next,
355  bi0, bi1, next0, next1);
356  }
357 
358  while (n_left_from > 0 && n_left_to_next > 0)
359  {
360  vlib_buffer_t *b0;
361  ip4_header_t *ip0;
362  ip4_fib_mtrie_t *mtrie0;
363  ip4_fib_mtrie_leaf_t leaf0;
365  ip_adjacency_t *adj0 = 0;
366  u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
367  udp_header_t *udp0;
368 
369  bi0 = from[0];
370  to_next[0] = bi0;
371  from += 1;
372  to_next += 1;
373  n_left_from -= 1;
374  n_left_to_next -= 1;
375 
376  b0 = vlib_get_buffer (vm, bi0);
377 
378  fib_index0 =
380  vnet_buffer (b0)->sw_if_index[VLIB_RX]);
381 
382  ip0 = vlib_buffer_get_current (b0);
383 
385  (&cm->config_main, &b0->current_config_index,
386  &next0, sizeof (c0[0]));
387 
388  /* we can't use the default VRF here... */
389  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
390  {
391  ASSERT (c0->fib_index[i]);
392  }
393 
394 
395  if (ip0->protocol == IP_PROTOCOL_UDP)
396  fib_index0 =
398  if (ip0->protocol == IP_PROTOCOL_TCP)
399  fib_index0 =
401 
402  if (fib_index0 != ~0)
403  {
404 
405  mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
406 
407  leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
408 
409  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
410  &ip0->src_address, 0);
411 
412  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
413  &ip0->src_address, 1);
414 
415  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
416  &ip0->src_address, 2);
417 
418  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
419  &ip0->src_address, 3);
420 
421  adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
422 
423  ASSERT (adj_index0 == ip4_fib_lookup_with_table
424  (im, fib_index0,
425  &ip0->src_address, 0 /* use default route */ ));
426  adj0 = ip_get_adjacency (lm, adj_index0);
427  }
428  /*
429  * $$$ which (src,dst) categories should we always pass?
430  */
431  pass0 = 0;
432  pass0 |= adj0 == 0;
433  pass0 |= ip4_address_is_multicast (&ip0->src_address);
434  pass0 |=
435  ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
436  pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
437  && (ip0->protocol != IP_PROTOCOL_TCP);
438 
439  save_next0 = next0;
440  udp0 = ip4_next_header (ip0);
441 
442  if (PREDICT_TRUE (pass0 == 0))
443  {
444  good_packets++;
446  (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
447  good_packets -= (save_next0 != next0);
448  b0->error = error_node->errors
449  [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
450  }
451 
453  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
454  {
456  vlib_add_trace (vm, node, b0, sizeof (*t));
457  t->pass = next0 == save_next0;
458  t->bypass = pass0;
459  t->fib_index = fib_index0;
460  t->src_addr.as_u32 = ip0->src_address.as_u32;
461  t->dst_port = (pass0 == 0) ?
462  clib_net_to_host_u16 (udp0->dst_port) : 0;
463  t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
464  }
465 
466  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
467  to_next, n_left_to_next,
468  bi0, next0);
469  }
470 
471  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
472  }
473 
474  vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
475  IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
476  good_packets);
477  return frame->n_vectors;
478 }
479 
480 static uword
482  vlib_node_runtime_t * node,
483  vlib_frame_t * frame)
484 {
485  return ip4_source_and_port_range_check_inline (vm, node, frame);
486 }
487 
488 /* *INDENT-OFF* */
489 VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
491  .name = "ip4-source-and-port-range-check",
492  .vector_size = sizeof (u32),
493 
494  .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
496 
498  .next_nodes = {
500  },
501 
502  .format_buffer = format_ip4_header,
504 };
505 /* *INDENT-ON* */
506 
507 int
509  u32 * fib_index,
510  u32 sw_if_index, u32 is_add)
511 {
512  ip4_main_t *im = &ip4_main;
513  ip_lookup_main_t *lm = &im->lookup_main;
515  u32 ci;
517  u32 feature_index;
518  int rv = 0;
519  int i;
520 
521  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
522  {
523  config.fib_index[i] = fib_index[i];
524  }
525 
527 
528  vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
529 
530  ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
531  ci = (is_add
534  (vm, &rx_cm->config_main, ci, feature_index, &config, sizeof (config));
535  rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
536 
537  return rv;
538 }
539 
540 static clib_error_t *
542  unformat_input_t * input,
543  vlib_cli_command_t * cmd)
544 {
545  vnet_main_t *vnm = vnet_get_main ();
546  ip4_main_t *im = &ip4_main;
547  clib_error_t *error = 0;
548  u8 is_add = 1;
549  u32 sw_if_index = ~0;
552  int vrf_set = 0;
553  uword *p;
554  int rv = 0;
555  int i;
556 
557  sw_if_index = ~0;
558  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
559  {
560  fib_index[i] = ~0;
561  vrf_id[i] = ~0;
562  }
563 
565  {
566  if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
567  &sw_if_index))
568  ;
569  else
570  if (unformat
571  (input, "tcp-out-vrf %d",
573  vrf_set = 1;
574  else
575  if (unformat
576  (input, "udp-out-vrf %d",
578  vrf_set = 1;
579  else
580  if (unformat
581  (input, "tcp-in-vrf %d",
583  vrf_set = 1;
584  else
585  if (unformat
586  (input, "udp-in-vrf %d",
588  vrf_set = 1;
589  else if (unformat (input, "del"))
590  is_add = 0;
591  else
592  break;
593  }
594 
595  if (sw_if_index == ~0)
596  return clib_error_return (0, "Interface required but not specified");
597 
598  if (!vrf_set)
599  return clib_error_return (0,
600  "TCP or UDP VRF ID required but not specified");
601 
602  for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
603  {
604 
605  if (vrf_id[i] == 0)
606  return clib_error_return (0,
607  "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
608 
609  if (vrf_id[i] != ~0)
610  {
611  p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
612 
613  if (p == 0)
614  return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
615 
616  fib_index[i] = p[0];
617  }
618  }
619  rv =
620  set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
621 
622  switch (rv)
623  {
624  case 0:
625  break;
626 
627  default:
628  return clib_error_return
629  (0,
630  "set source and port-range on interface returned an unexpected value: %d",
631  rv);
632  }
633  return error;
634 }
635 
636 /* *INDENT-OFF* */
637 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
638  static) = {
639  .path = "set interface ip source-and-port-range-check",
641  .short_help = "set int ip source-and-port-range-check <intfc> [tcp-out-vrf <n>] [udp-out-vrf <n>] [tcp-in-vrf <n>] [udp-in-vrf <n>] [del]",
642 };
643 /* *INDENT-ON* */
644 
645 static u8 *
647 {
648  CLIB_UNUSED (vnet_main_t * vnm) = va_arg (*args, vnet_main_t *);
649  ip_lookup_main_t *lm = va_arg (*args, ip_lookup_main_t *);
650  u32 adj_index = va_arg (*args, u32);
651  ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index);
653  u8 *rwh = (u8 *) (&adj->rewrite_header);
654  protocol_port_range_t *range;
655  int i, j;
656  int printed = 0;
657 
658  range = (protocol_port_range_t *) rwh;
659 
660  s = format (s, "allow ");
661 
662  for (i = 0; i < srm->ranges_per_adjacency; i++)
663  {
664  for (j = 0; j < 8; j++)
665  {
666  if (range->low.as_u16[j])
667  {
668  if (printed)
669  s = format (s, ", ");
670  if (range->hi.as_u16[j] > (range->low.as_u16[j] + 1))
671  s = format (s, "%d-%d", (u32) range->low.as_u16[j],
672  (u32) range->hi.as_u16[j] - 1);
673  else
674  s = format (s, "%d", range->low.as_u16[j]);
675  printed = 1;
676  }
677  }
678  range++;
679  }
680  return s;
681 }
682 
683 clib_error_t *
685 {
687  ip4_main_t *im = &ip4_main;
688  ip_lookup_main_t *lm = &im->lookup_main;
689 
690  srm->vlib_main = vm;
691  srm->vnet_main = vnet_get_main ();
692 
693  srm->ranges_per_adjacency =
694  VLIB_BUFFER_PRE_DATA_SIZE / (2 * sizeof (u16x8));
699 
700  return 0;
701 }
702 
704 
705 int
707  u32 length,
708  u32 adj_index,
709  u16 * low_ports, u16 * high_ports, u32 fib_index)
710 {
711  ip_adjacency_t *adj;
712  int i, j, k;
714  ip4_main_t *im = &ip4_main;
715  ip_lookup_main_t *lm = &im->lookup_main;
716  protocol_port_range_t *range;
717  u8 *rwh;
718 
719  adj = ip_get_adjacency (lm, adj_index);
720  /* $$$$ fixme: add ports if address + mask match */
722  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
723 
724  ip_adjacency_t template_adj;
726 
727  memset (&template_adj, 0, sizeof (template_adj));
728 
730  template_adj.if_address_index = ~0;
733 
734  rwh = (u8 *) (&template_adj.rewrite_header);
735 
736  range = (protocol_port_range_t *) rwh;
737 
738  if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
739  return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
740 
741  j = k = 0;
742 
743  for (i = 0; i < vec_len (low_ports); i++)
744  {
745  for (; j < srm->ranges_per_adjacency; j++)
746  {
747  for (; k < 8; k++)
748  {
749  if (range->low.as_u16[k] == 0)
750  {
751  range->low.as_u16[k] = low_ports[i];
752  range->hi.as_u16[k] = high_ports[i];
753  k++;
754  if (k == 7)
755  {
756  k = 0;
757  j++;
758  }
759  goto doublebreak2;
760  }
761  }
762  k = 0;
763  range++;
764  }
765  j = 0;
766  /* Too many ports specified... */
767  return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
768 
769  doublebreak2:;
770  }
771 
772  memset (&a, 0, sizeof (a));
774  a.table_index_or_table_id = fib_index;
775  a.dst_address = address[0];
776  a.dst_address_length = length;
777  a.add_adj = &template_adj;
778  a.n_add_adj = 1;
779 
780  ip4_add_del_route (im, &a);
781  return 0;
782 }
783 
784 int
786  u32 length,
787  u32 adj_index,
788  u16 * low_ports, u16 * high_ports, u32 fib_index)
789 {
790  ip_adjacency_t *adj;
791  int i, j, k;
793  ip4_main_t *im = &ip4_main;
794  ip_lookup_main_t *lm = &im->lookup_main;
795  protocol_port_range_t *range;
796  u8 *rwh;
797 
798  adj = ip_get_adjacency (lm, adj_index);
799  if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR) /* _ICMP_ERROR is a dummy placeholder */
800  return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
801 
802  rwh = (u8 *) (&adj->rewrite_header);
803 
804  for (i = 0; i < vec_len (low_ports); i++)
805  {
806  range = (protocol_port_range_t *) rwh;
807  for (j = 0; j < srm->ranges_per_adjacency; j++)
808  {
809  for (k = 0; k < 8; k++)
810  {
811  if (low_ports[i] == range->low.as_u16[k] &&
812  high_ports[i] == range->hi.as_u16[k])
813  {
814  range->low.as_u16[k] = range->hi.as_u16[k] = 0;
815  goto doublebreak;
816  }
817  }
818  range++;
819  }
820  doublebreak:;
821  }
822 
823  range = (protocol_port_range_t *) rwh;
824  /* Have we deleted all ranges yet? */
825  for (i = 0; i < srm->ranges_per_adjacency; i++)
826  {
827  for (j = 0; j < 8; j++)
828  {
829  if (range->low.as_u16[i] != 0)
830  goto still_occupied;
831  }
832  range++;
833  }
834  /* Yes, lose the adjacency... */
835  {
837 
838  memset (&a, 0, sizeof (a));
840  a.table_index_or_table_id = fib_index;
841  a.dst_address = address[0];
842  a.dst_address_length = length;
843  a.adj_index = adj_index;
844  ip4_add_del_route (im, &a);
845  }
846 
847 still_occupied:
848  ;
849  return 0;
850 }
851 
852 // This will be moved to another file and implemented post API freeze.
853 int
855  u32 length,
856  u32 vrf_id,
857  u16 * low_ports,
858  u16 * high_ports, int is_add)
859 {
860  return 0;
861 }
862 
863 int
865  u32 length,
866  u32 vrf_id,
867  u16 * low_ports,
868  u16 * high_ports, int is_add)
869 {
870 
871  ip4_main_t *im = &ip4_main;
872  // ip_lookup_main_t * lm = &im->lookup_main;
873  uword *p;
874  u32 fib_index;
875  u32 adj_index;
876 
877  p = hash_get (im->fib_index_by_table_id, vrf_id);
878  if (!p)
879  {
880  ip4_fib_t *f;
881  f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */ );
882  fib_index = f->index;
883  }
884  else
885  fib_index = p[0];
886 
887  adj_index = ip4_fib_lookup_with_table
888  (im, fib_index, address, 0 /* disable_default_route */ );
889 
890  if (is_add == 0)
891  {
892  remove_port_range_adjacency (address, length, adj_index, low_ports,
893  high_ports, fib_index);
894  }
895  else
896  {
897  add_port_range_adjacency (address, length, adj_index, low_ports,
898  high_ports, fib_index);
899  }
900 
901  return 0;
902 }
903 
904 static clib_error_t *
906  unformat_input_t * input,
907  vlib_cli_command_t * cmd)
908 {
909  u16 *low_ports = 0;
910  u16 *high_ports = 0;
911  u16 this_low;
912  u16 this_hi;
913  ip4_address_t ip4_addr;
914  ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
915  u32 length;
916  u32 tmp, tmp2;
917  u32 vrf_id = ~0;
918  int is_add = 1, ip_ver = ~0;
919  int rv;
920 
921 
923  {
924  if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
925  ip_ver = 4;
926  else
927  if (unformat
928  (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
929  ip_ver = 6;
930  else if (unformat (input, "vrf %d", &vrf_id))
931  ;
932  else if (unformat (input, "del"))
933  is_add = 0;
934  else if (unformat (input, "port %d", &tmp))
935  {
936  if (tmp == 0 || tmp > 65535)
937  return clib_error_return (0, "port %d out of range", tmp);
938  this_low = tmp;
939  this_hi = this_low + 1;
940  vec_add1 (low_ports, this_low);
941  vec_add1 (high_ports, this_hi);
942  }
943  else if (unformat (input, "range %d - %d", &tmp, &tmp2))
944  {
945  if (tmp > tmp2)
946  return clib_error_return (0, "ports %d and %d out of order",
947  tmp, tmp2);
948  if (tmp == 0 || tmp > 65535)
949  return clib_error_return (0, "low port %d out of range", tmp);
950  if (tmp2 == 0 || tmp2 > 65535)
951  return clib_error_return (0, "high port %d out of range", tmp2);
952  this_low = tmp;
953  this_hi = tmp2 + 1;
954  vec_add1 (low_ports, this_low);
955  vec_add1 (high_ports, this_hi);
956  }
957  else
958  break;
959  }
960 
961  if (ip_ver == ~0)
962  return clib_error_return (0, " <address>/<mask> not specified");
963 
964  if (vrf_id == ~0)
965  return clib_error_return (0, " VRF ID required, not specified");
966 
967  if (vec_len (low_ports) == 0)
968  return clib_error_return (0,
969  " Both VRF ID and range/port must be set for a protocol.");
970 
971  if (vrf_id == 0)
972  return clib_error_return (0, " VRF ID can not be 0 (default).");
973 
974 
975  if (ip_ver == 4)
977  (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
978  else
979  return clib_error_return (0, " IPv6 in subsequent patch");
980 
981  switch (rv)
982  {
983  case 0:
984  break;
985 
986  case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
987  return clib_error_return
988  (0, " Incorrect adjacency for add/del operation");
989 
990  case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
991  return clib_error_return (0, " Too many ports in add/del operation");
992 
993  case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
994  return clib_error_return
995  (0, " Too many ranges requested for add operation");
996 
997  default:
998  return clib_error_return (0, " returned an unexpected value: %d", rv);
999  }
1000 
1001  return 0;
1002 }
1003 
1004 /* *INDENT-OFF* */
1005 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
1006  .path = "set ip source-and-port-range-check",
1008  .short_help =
1009  "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn>-<nn> tcp-vrf <id>] [vrf <id>] [del]",
1010 };
1011 /* *INDENT-ON* */
1012 
1013 
1014 static clib_error_t *
1016  unformat_input_t * input,
1017  vlib_cli_command_t * cmd)
1018 {
1020  ip4_main_t *im = &ip4_main;
1021  ip_lookup_main_t *lm = &im->lookup_main;
1022  protocol_port_range_t *range;
1023  u32 fib_index;
1025  u8 addr_set = 0;
1026  u32 vrf_id = ~0;
1027  int rv, i, j;
1028  u32 adj_index;
1029  ip_adjacency_t *adj;
1030  u32 port = 0;
1031  u8 *rwh;
1032  uword *p;
1033 
1034  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1035  {
1036  if (unformat (input, "%U", unformat_ip4_address, &addr))
1037  addr_set = 1;
1038  else if (unformat (input, "vrf %d", &vrf_id))
1039  ;
1040  else if (unformat (input, "port %d", &port))
1041  ;
1042  else
1043  break;
1044  }
1045 
1046  if (addr_set == 0)
1047  return clib_error_return (0, "<address> not specified");
1048 
1049  if (vrf_id == ~0)
1050  return clib_error_return (0, "VRF ID required, not specified");
1051 
1052  p = hash_get (im->fib_index_by_table_id, vrf_id);
1053  if (p == 0)
1054  return clib_error_return (0, "VRF %d not found", vrf_id);
1055  fib_index = p[0];
1056 
1057  adj_index = ip4_fib_lookup_with_table
1058  (im, fib_index, &addr, 0 /* disable_default_route */ );
1059 
1060  adj = ip_get_adjacency (lm, adj_index);
1061 
1063  {
1064  vlib_cli_output (vm, "%U: src address drop", format_ip4_address, &addr);
1065  return 0;
1066  }
1067 
1068  if (port)
1069  {
1070  rv = check_adj_port_range_x1 (adj, (u16) port, 1234);
1071  if (rv == 1234)
1072  vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
1073  &addr, port);
1074  else
1075  vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
1076  &addr, port);
1077  return 0;
1078  }
1079  else
1080  {
1081  u8 *s;
1082  rwh = (u8 *) (&adj->rewrite_header);
1083 
1084  s = format (0, "%U: ", format_ip4_address, &addr);
1085 
1086  range = (protocol_port_range_t *) rwh;
1087 
1088  for (i = 0; i < srm->ranges_per_adjacency; i++)
1089  {
1090  for (j = 0; j < 8; j++)
1091  {
1092  if (range->low.as_u16[j])
1093  s = format (s, "%d - %d ", (u32) range->low.as_u16[j],
1094  (u32) range->hi.as_u16[j]);
1095  }
1096  range++;
1097  }
1098  vlib_cli_output (vm, "%s", s);
1099  vec_free (s);
1100  }
1101 
1102  return 0;
1103 }
1104 
1105 /* *INDENT-OFF* */
1106 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
1107  .path = "show ip source-and-port-range-check",
1109  .short_help =
1110  "show ip source-and-port-range-check vrf <nn> <ip-addr> <port>",
1111 };
1112 /* *INDENT-ON* */
1113 
1114 /*
1115  * fd.io coding-style-patch-verification: ON
1116  *
1117  * Local Variables:
1118  * eval: (c-set-style "gnu")
1119  * End:
1120  */
#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
static u8 * format_ip4_source_and_port_range_check_trace(u8 *s, va_list *va)
ip4_fib_t * find_ip4_fib_by_table_index_or_id(ip4_main_t *im, u32 table_index_or_id, u32 flags)
Get or create an IPv4 fib.
Definition: ip4_forward.c:120
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
u32 * config_index_by_sw_if_index
Definition: lookup.h:369
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
a
Definition: bitmap.h:516
static u8 * format_source_and_port_rc_adjacency(u8 *s, va_list *args)
u32 current_config_index
Used by feature subgraph arcs to visit enabled feature nodes.
Definition: buffer.h:121
ip4_address_t src_address
Definition: ip4_packet.h:138
ip_lookup_next_t lookup_next_index
Definition: lookup.h:180
#define PREDICT_TRUE(x)
Definition: clib.h:98
IP unicast adjacency.
Definition: lookup.h:164
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#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
ip_config_main_t rx_config_mains[VNET_N_CAST]
rx/tx interface/feature configuration.
Definition: lookup.h:452
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
u32 special_adjacency_format_function_index
Special format function for this adjacency.
Definition: lookup.h:212
struct _vlib_node_registration vlib_node_registration_t
ip_lookup_main_t lookup_main
Definition: ip4.h:115
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:123
unformat_function_t unformat_vnet_sw_interface
vlib_error_t * errors
Definition: node.h:418
format_function_t format_ip4_address
Definition: format.h:71
u32 index
Definition: ip4.h:62
int remove_port_range_adjacency(ip4_address_t *address, u32 length, u32 adj_index, u16 *low_ports, u16 *high_ports, u32 fib_index)
static uword ip4_source_and_port_range_check_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
This packets needs to go to ICMP error.
Definition: lookup.h:93
#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:187
u32 ip4_fib_mtrie_leaf_t
Definition: ip4_mtrie.h:52
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u32 ip4_fib_lookup_with_table(ip4_main_t *im, u32 fib_index, ip4_address_t *dst, u32 disable_default_route)
Definition: ip4_forward.c:58
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)
ip4_source_and_port_range_check_next_t
static u32 ip4_fib_mtrie_leaf_get_adj_index(ip4_fib_mtrie_leaf_t n)
Definition: ip4_mtrie.h:66
unformat_function_t unformat_ip4_address
Definition: format.h:68
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:52
#define hash_get(h, key)
Definition: hash.h:248
static u16x8 u16x8_is_equal(u16x8 x, u16x8 y)
Definition: vector_sse2.h:492
int add_port_range_adjacency(ip4_address_t *address, u32 length, u32 adj_index, u16 *low_ports, u16 *high_ports, u32 fib_index)
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:127
#define u16x8_splat(i)
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 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 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_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
static ip4_fib_mtrie_leaf_t ip4_fib_mtrie_lookup_step(ip4_fib_mtrie_t *m, ip4_fib_mtrie_leaf_t current_leaf, ip4_address_t *dst_address, u32 dst_address_byte_index)
Definition: ip4_mtrie.h:145
#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:130
#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:348
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:118
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1111
unformat_function_t unformat_ip6_address
Definition: format.h:86
ip_adjacency_t * add_adj
Definition: ip4.h:337
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
Definition: ip4.h:48
#define ARRAY_LEN(x)
Definition: clib.h:59
#define IP4_ROUTE_FLAG_DEL
Definition: ip4.h:309
u16 cached_next_index
Definition: node.h:462
#define ASSERT(truth)
#define IP4_FIB_MTRIE_LEAF_ROOT
Definition: ip4_mtrie.h:55
format_function_t format_ip4_header
Definition: format.h:78
unsigned int u32
Definition: types.h:88
source_range_check_main_t source_range_check_main
ip4_fib_t * fibs
Vector of FIBs.
Definition: ip4.h:118
ip4_address_t dst_address
Definition: ip4.h:328
#define vnet_buffer(b)
Definition: buffer.h:335
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
IPv4 main type.
Definition: ip4.h:114
#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:93
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
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
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
#define IP4_ROUTE_FLAG_FIB_INDEX
Definition: ip4.h:311
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
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)
u32 table_index_or_table_id
Definition: ip4.h:325
static uword ip4_source_and_port_range_check(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
u32 ip4_unicast_rx_feature_source_and_port_range_check
Built-in unicast feature path indice, see ip_feature_init_cast()
Definition: ip4.h:160
u8 data[0]
Packet data.
Definition: buffer.h:151
u32 if_address_index
Interface address index for this local/arp adjacency.
Definition: lookup.h:172
u32 vnet_register_special_adjacency_format_function(ip_lookup_main_t *lm, format_function_t *fp)
Definition: lookup.c:1013
vhost_vring_addr_t addr
Definition: vhost-user.h:82
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
static u32 check_adj_port_range_x1(ip_adjacency_t *adj, u16 dst_port, u32 next)
void ip4_add_del_route(ip4_main_t *im, ip4_add_del_route_args_t *args)
Definition: ip4_forward.c:228
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
vnet_config_main_t config_main
Definition: lookup.h:367
Definition: defs.h:46
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480
u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS]
vlib_node_registration_t ip4_source_port_and_range_check
(constructor) VLIB_REGISTER_NODE (ip4_source_port_and_range_check)
int set_ip_source_and_port_range_check(vlib_main_t *vm, u32 *fib_index, u32 sw_if_index, u32 is_add)