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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/ip/ip.h>
18 u32 ranges_per_adjacency;
19 u32 special_adjacency_format_function_index;
22 vlib_main_t *vlib_main;
23 vnet_main_t *vnet_main;
24 } source_range_check_main_t;
26 source_range_check_main_t source_range_check_main;
28 vlib_node_registration_t ip4_source_port_and_range_check;
42 #define foreach_ip4_source_and_port_range_check_error \
43 _(CHECK_FAIL, "ip4 source and port range check bad packets") \
44 _(CHECK_OK, "ip4 source and port range check good packets")
47 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
48 foreach_ip4_source_and_port_range_check_error
50 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_ERROR,
51 } ip4_source_and_port_range_check_error_t;
53 static char * ip4_source_and_port_range_check_error_strings[] = {
54 #define _(sym,string) string,
55 foreach_ip4_source_and_port_range_check_error
63 ip4_address_t src_addr;
65 } ip4_source_and_port_range_check_trace_t;
67 static u8 * format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
69 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
70 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
71 ip4_source_and_port_range_check_trace_t * t =
72 va_arg (*va, ip4_source_and_port_range_check_trace_t *);
75 s = format (s, "PASS (bypass case)");
77 s = format (s, "src ip %U %s dst port %d: %s",
78 format_ip4_address, &t->src_addr, t->is_tcp ? "TCP" : "UDP",
80 (t->pass == 1) ? "PASS" : "FAIL");
85 IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP,
86 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
87 } ip4_source_and_port_range_check_next_t;
91 } ip4_source_and_port_range_check_config_t;
93 static inline u32 check_adj_port_range_x1 (ip_adjacency_t * adj,
101 u16x8vec_t sum, sum_equal_diff2;
102 u16 sum_nonzero, sum_equal, winner_mask;
106 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR || dst_port == 0)
107 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
109 rwh = (u8 *)(&adj->rewrite_header);
110 range = (port_range_t *)rwh;
112 /* Make the obvious screw-case work. A variant also works w/ no MMX */
113 if (PREDICT_FALSE(dst_port == 65535))
117 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(port_range_t); i++)
119 for (j = 0; j < 8; j++)
120 if (range->low.as_u16x8[j] == 65535)
124 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
127 key.as_u16x8 = u16x8_splat (dst_port);
129 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(port_range_t); i++)
131 diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
132 diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
133 sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
134 sum_equal_diff2.as_u16x8 = u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
135 sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
136 sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
137 winner_mask = sum_nonzero & sum_equal;
142 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
146 ip4_source_and_port_range_check_inline
147 (vlib_main_t * vm, vlib_node_runtime_t * node,
148 vlib_frame_t * frame)
150 ip4_main_t * im = &ip4_main;
151 ip_lookup_main_t * lm = &im->lookup_main;
152 ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
153 u32 n_left_from, * from, * to_next;
155 vlib_node_runtime_t * error_node = node;
156 u32 good_packets = 0;
158 from = vlib_frame_vector_args (frame);
159 n_left_from = frame->n_vectors;
160 next_index = node->cached_next_index;
162 while (n_left_from > 0)
166 vlib_get_next_frame (vm, node, next_index,
167 to_next, n_left_to_next);
169 while (n_left_from >= 4 && n_left_to_next >= 2)
171 vlib_buffer_t * b0, * b1;
172 ip4_header_t * ip0, * ip1;
173 ip4_fib_mtrie_t * mtrie0, * mtrie1;
174 ip4_fib_mtrie_leaf_t leaf0, leaf1;
175 ip4_source_and_port_range_check_config_t * c0, * c1;
176 ip_adjacency_t * adj0, * adj1;
177 u32 bi0, next0, adj_index0, pass0, save_next0;
178 u32 bi1, next1, adj_index1, pass1, save_next1;
179 udp_header_t * udp0, * udp1;
181 /* Prefetch next iteration. */
183 vlib_buffer_t * p2, * p3;
185 p2 = vlib_get_buffer (vm, from[2]);
186 p3 = vlib_get_buffer (vm, from[3]);
188 vlib_prefetch_buffer_header (p2, LOAD);
189 vlib_prefetch_buffer_header (p3, LOAD);
191 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
192 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
195 bi0 = to_next[0] = from[0];
196 bi1 = to_next[1] = from[1];
202 b0 = vlib_get_buffer (vm, bi0);
203 b1 = vlib_get_buffer (vm, bi1);
205 ip0 = vlib_buffer_get_current (b0);
206 ip1 = vlib_buffer_get_current (b1);
208 c0 = vnet_get_config_data (&cm->config_main,
209 &b0->current_config_index,
212 c1 = vnet_get_config_data (&cm->config_main,
213 &b1->current_config_index,
217 /* we can't use the default VRF here... */
218 ASSERT (c0->fib_index && c1->fib_index);
220 mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
221 mtrie1 = &vec_elt_at_index (im->fibs, c1->fib_index)->mtrie;
223 leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
225 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
226 &ip0->src_address, 0);
227 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
228 &ip1->src_address, 0);
230 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
231 &ip0->src_address, 1);
232 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
233 &ip1->src_address, 1);
235 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
236 &ip0->src_address, 2);
237 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
238 &ip1->src_address, 2);
240 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
241 &ip0->src_address, 3);
242 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
243 &ip1->src_address, 3);
245 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
246 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
248 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
250 0 /* use dflt rt */));
252 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, c1->fib_index,
255 adj0 = ip_get_adjacency (lm, adj_index0);
256 adj1 = ip_get_adjacency (lm, adj_index1);
259 pass0 |= ip4_address_is_multicast (&ip0->src_address);
260 pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
261 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
262 (ip0->protocol != IP_PROTOCOL_TCP);
265 pass1 |= ip4_address_is_multicast (&ip1->src_address);
266 pass1 |= ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
267 pass1 |= (ip1->protocol != IP_PROTOCOL_UDP) &&
268 (ip1->protocol != IP_PROTOCOL_TCP);
271 udp0 = ip4_next_header (ip0);
273 udp1 = ip4_next_header (ip1);
275 if (PREDICT_TRUE(pass0 == 0))
278 next0 = check_adj_port_range_x1
279 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
280 good_packets -= (save_next0 != next0);
281 b0->error = error_node->errors
282 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
285 if (PREDICT_TRUE(pass1 == 0))
288 next1 = check_adj_port_range_x1
289 (adj1, clib_net_to_host_u16(udp1->dst_port), next1);
290 good_packets -= (save_next1 != next1);
291 b1->error = error_node->errors
292 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
295 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
296 && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
297 ip4_source_and_port_range_check_trace_t * t =
298 vlib_add_trace (vm, node, b0, sizeof (*t));
299 t->pass = next0 == save_next0;
301 t->src_addr.as_u32 = ip0->src_address.as_u32;
302 t->dst_port = (pass0 == 0) ?
303 clib_net_to_host_u16(udp0->dst_port) : 0;
304 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
307 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
308 && (b1->flags & VLIB_BUFFER_IS_TRACED))) {
309 ip4_source_and_port_range_check_trace_t * t =
310 vlib_add_trace (vm, node, b1, sizeof (*t));
311 t->pass = next1 == save_next1;
313 t->src_addr.as_u32 = ip1->src_address.as_u32;
314 t->dst_port = (pass1 == 0) ?
315 clib_net_to_host_u16(udp1->dst_port) : 0;
316 t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
319 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
320 to_next, n_left_to_next,
321 bi0, bi1, next0, next1);
324 while (n_left_from > 0 && n_left_to_next > 0)
328 ip4_fib_mtrie_t * mtrie0;
329 ip4_fib_mtrie_leaf_t leaf0;
330 ip4_source_and_port_range_check_config_t * c0;
331 ip_adjacency_t * adj0;
332 u32 bi0, next0, adj_index0, pass0, save_next0;
342 b0 = vlib_get_buffer (vm, bi0);
343 ip0 = vlib_buffer_get_current (b0);
345 c0 = vnet_get_config_data
346 (&cm->config_main, &b0->current_config_index,
350 /* we can't use the default VRF here... */
351 ASSERT(c0->fib_index);
353 mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
355 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
357 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
358 &ip0->src_address, 0);
360 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
361 &ip0->src_address, 1);
363 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
364 &ip0->src_address, 2);
366 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
367 &ip0->src_address, 3);
369 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
371 ASSERT (adj_index0 == ip4_fib_lookup_with_table
374 0 /* use default route */));
375 adj0 = ip_get_adjacency (lm, adj_index0);
378 * $$$ which (src,dst) categories should we always pass?
381 pass0 |= ip4_address_is_multicast (&ip0->src_address);
382 pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
383 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
384 (ip0->protocol != IP_PROTOCOL_TCP);
387 udp0 = ip4_next_header (ip0);
389 if (PREDICT_TRUE(pass0 == 0))
392 next0 = check_adj_port_range_x1
393 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
394 good_packets -= (save_next0 != next0);
395 b0->error = error_node->errors
396 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
399 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
400 && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
401 ip4_source_and_port_range_check_trace_t * t =
402 vlib_add_trace (vm, node, b0, sizeof (*t));
403 t->pass = next0 == save_next0;
405 t->src_addr.as_u32 = ip0->src_address.as_u32;
406 t->dst_port = (pass0 == 0) ?
407 clib_net_to_host_u16(udp0->dst_port) : 0;
408 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
411 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
412 to_next, n_left_to_next,
416 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
419 vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
420 IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
422 return frame->n_vectors;
426 ip4_source_and_port_range_check (vlib_main_t * vm,
427 vlib_node_runtime_t * node,
428 vlib_frame_t * frame)
430 return ip4_source_and_port_range_check_inline (vm, node, frame);
433 VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
434 .function = ip4_source_and_port_range_check,
435 .name = "ip4-source-and-port-range-check",
436 .vector_size = sizeof (u32),
438 .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
439 .error_strings = ip4_source_and_port_range_check_error_strings,
441 .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
443 [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
446 .format_buffer = format_ip4_header,
447 .format_trace = format_ip4_source_and_port_range_check_trace,
450 int set_ip_source_and_port_range_check (vlib_main_t * vm,
455 ip4_main_t * im = &ip4_main;
456 ip_lookup_main_t * lm = &im->lookup_main;
457 ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
459 ip4_source_and_port_range_check_config_t config;
464 config.fib_index = fib_index;
465 feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
467 vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
469 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
471 ? vnet_config_del_feature
472 : vnet_config_add_feature)
473 (vm, &rx_cm->config_main,
478 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
483 static clib_error_t *
484 set_ip_source_and_port_range_check_fn (vlib_main_t * vm,
485 unformat_input_t * input,
486 vlib_cli_command_t * cmd)
488 vnet_main_t * vnm = vnet_get_main();
489 ip4_main_t * im = &ip4_main;
490 clib_error_t * error = 0;
492 u32 sw_if_index = ~0;
500 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
502 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
505 else if (unformat (input, "vrf %d", &vrf_id))
507 else if (unformat (input, "del"))
513 if (sw_if_index == ~0)
514 return clib_error_return (0, "Interface required but not specified");
517 return clib_error_return (0, "VRF ID required but not specified");
520 return clib_error_return (0, "VRF ID should not be default. Should be distinct VRF for this purpose. ");
522 p = hash_get (im->fib_index_by_table_id, vrf_id);
525 return clib_error_return (0, "Invalid VRF ID %d", vrf_id);
528 rv = set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
536 return clib_error_return
537 (0, "set source and port-range on interface returned an unexpected value: %d", rv);
542 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
544 .path = "set interface ip source-and-port-range-check",
545 .function = set_ip_source_and_port_range_check_fn,
546 .short_help = "set int ip source-and-port-range-check <intfc> vrf <n> [del]",
549 static u8 * format_source_and_port_rc_adjacency (u8 * s, va_list * args)
551 CLIB_UNUSED (vnet_main_t * vnm) = va_arg (*args, vnet_main_t *);
552 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
553 u32 adj_index = va_arg (*args, u32);
554 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
555 source_range_check_main_t * srm = &source_range_check_main;
556 u8 * rwh = (u8 *) (&adj->rewrite_header);
557 port_range_t * range;
561 range = (port_range_t *) rwh;
563 s = format (s, "allow ");
565 for (i = 0; i < srm->ranges_per_adjacency; i++)
567 for (j = 0; j < 8; j++)
569 if (range->low.as_u16[j])
572 s = format (s, ", ");
573 if (range->hi.as_u16[j] > (range->low.as_u16[j] + 1))
574 s = format (s, "%d-%d", (u32) range->low.as_u16[j],
575 (u32) range->hi.as_u16[j] - 1);
577 s = format (s, "%d", range->low.as_u16[j]);
586 clib_error_t * ip4_source_and_port_range_check_init (vlib_main_t * vm)
588 source_range_check_main_t * srm = &source_range_check_main;
589 ip4_main_t * im = &ip4_main;
590 ip_lookup_main_t * lm = &im->lookup_main;
593 srm->vnet_main = vnet_get_main();
595 srm->ranges_per_adjacency = VLIB_BUFFER_PRE_DATA_SIZE / (2*sizeof(u16x8));
596 srm->special_adjacency_format_function_index =
597 vnet_register_special_adjacency_format_function
598 (lm, format_source_and_port_rc_adjacency);
599 ASSERT (srm->special_adjacency_format_function_index);
604 VLIB_INIT_FUNCTION (ip4_source_and_port_range_check_init);
607 int ip4_source_and_port_range_check_add_del
608 (ip4_address_t * address, u32 length, u32 vrf_id, u16 * low_ports,
609 u16 * hi_ports, int is_add)
611 source_range_check_main_t * srm = &source_range_check_main;
612 ip4_main_t * im = &ip4_main;
613 ip_lookup_main_t * lm = &im->lookup_main;
617 ip_adjacency_t * adj;
619 port_range_t * range;
622 p = hash_get (im->fib_index_by_table_id, vrf_id);
626 f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */);
627 fib_index = f->index;
632 adj_index = ip4_fib_lookup_with_table
633 (im, fib_index, address, 0 /* disable_default_route */);
637 adj = ip_get_adjacency (lm, adj_index);
638 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
639 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
641 rwh = (u8 *)(&adj->rewrite_header);
643 for (i = 0; i < vec_len (low_ports); i++)
645 range = (port_range_t *) rwh;
646 for (j = 0; j < srm->ranges_per_adjacency; j++)
648 for (k = 0; k < 8; k++)
650 if (low_ports[i] == range->low.as_u16[k] &&
651 hi_ports[i] == range->hi.as_u16[k])
653 range->low.as_u16[k] = range->hi.as_u16[k] = 0;
662 range = (port_range_t *) rwh;
663 /* Have we deleted all ranges yet? */
664 for (i = 0; i < srm->ranges_per_adjacency; i++)
666 for (j = 0; j < 8; j++)
668 if (range->low.as_u16[i] != 0)
673 /* Yes, lose the adjacency... */
675 ip4_add_del_route_args_t a;
677 memset (&a, 0, sizeof(a));
678 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
679 a.table_index_or_table_id = fib_index;
680 a.dst_address = address[0];
681 a.dst_address_length = length;
682 a.adj_index = adj_index;
683 ip4_add_del_route (im, &a);
691 adj = ip_get_adjacency (lm, adj_index);
692 /* $$$$ fixme: add ports if address + mask match */
693 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
694 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
697 ip_adjacency_t template_adj;
698 ip4_add_del_route_args_t a;
700 memset (&template_adj, 0, sizeof (template_adj));
702 template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
703 template_adj.if_address_index = ~0;
704 template_adj.special_adjacency_format_function_index =
705 srm->special_adjacency_format_function_index;
707 rwh = (u8 *) (&template_adj.rewrite_header);
709 range = (port_range_t *) rwh;
711 if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
712 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
716 for (i = 0; i < vec_len (low_ports); i++)
718 for (; j < srm->ranges_per_adjacency; j++)
722 if (range->low.as_u16[k] == 0)
724 range->low.as_u16[k] = low_ports[i];
725 range->hi.as_u16[k] = hi_ports[i];
739 /* Too many ports specified... */
740 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
745 memset (&a, 0, sizeof(a));
746 a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
747 a.table_index_or_table_id = fib_index;
748 a.dst_address = address[0];
749 a.dst_address_length = length;
750 a.add_adj = &template_adj;
753 ip4_add_del_route (im, &a);
760 static clib_error_t *
761 ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
762 unformat_input_t * input,
763 vlib_cli_command_t * cmd)
766 u16 * high_ports = 0;
777 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
779 if (unformat (input, "%U/%d", unformat_ip4_address, &addr, &length))
781 else if (unformat (input, "vrf %d", &vrf_id))
783 else if (unformat (input, "del"))
785 else if (unformat (input, "port %d", &tmp))
787 if (tmp == 0 || tmp > 65535)
788 return clib_error_return (0, "port %d out of range", tmp);
790 this_hi = this_low + 1;
791 vec_add1 (low_ports, this_low);
792 vec_add1 (high_ports, this_hi);
794 else if (unformat (input, "range %d - %d", &tmp, &tmp2))
797 return clib_error_return (0, "ports %d and %d out of order",
799 if (tmp == 0 || tmp > 65535)
800 return clib_error_return (0, "low port %d out of range", tmp);
801 if (tmp2 == 0 || tmp2 > 65535)
802 return clib_error_return (0, "hi port %d out of range", tmp2);
805 vec_add1 (low_ports, this_low);
806 vec_add1 (high_ports, this_hi);
813 return clib_error_return (0, "<address>/<mask> not specified");
816 return clib_error_return (0, "VRF ID required, not specified");
819 return clib_error_return (0, "VRF ID should not be default. Should be distinct VRF for this purpose. ");
821 if (vec_len(low_ports) == 0)
822 return clib_error_return (0, "At least one port or port range required");
824 rv = ip4_source_and_port_range_check_add_del
825 (&addr, length, vrf_id, low_ports, high_ports, is_add);
832 case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
833 return clib_error_return
834 (0, "Incorrect adjacency for add/del operation in ip4 source and port-range check.");
836 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
837 return clib_error_return
838 (0, "Too many ports in add/del operation in ip4 source and port-range check.");
840 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
841 return clib_error_return
842 (0, "Too many ranges requested for add operation in ip4 source and port-range check.");
845 return clib_error_return
846 (0, "ip4_source_and_port_range_check_add returned an unexpected value: %d", rv);
852 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
853 .path = "set ip source-and-port-range-check",
854 .function = ip_source_and_port_range_check_command_fn,
856 "set ip source-and-port-range-check <ip-addr>/<mask> range <nn>-<nn> vrf <id>",
860 static clib_error_t *
861 show_source_and_port_range_check_fn (vlib_main_t * vm,
862 unformat_input_t * input,
863 vlib_cli_command_t * cmd)
865 source_range_check_main_t * srm = & source_range_check_main;
866 ip4_main_t * im = &ip4_main;
867 ip_lookup_main_t * lm = &im->lookup_main;
868 port_range_t * range;
880 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
882 if (unformat (input, "%U", unformat_ip4_address, &addr))
884 else if (unformat (input, "vrf %d", &vrf_id))
886 else if (unformat (input, "port %d", &port))
893 return clib_error_return (0, "<address> not specified");
896 return clib_error_return (0, "VRF ID required, not specified");
898 p = hash_get (im->fib_index_by_table_id, vrf_id);
900 return clib_error_return (0, "VRF %d not found", vrf_id);
903 adj_index = ip4_fib_lookup_with_table
904 (im, fib_index, &addr, 0 /* disable_default_route */);
906 adj = ip_get_adjacency (lm, adj_index);
908 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
910 vlib_cli_output (vm, "%U: src address drop", format_ip4_address, &addr);
916 rv = check_adj_port_range_x1 (adj, (u16) port, 1234);
918 vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
921 vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
928 rwh = (u8 *) (&adj->rewrite_header);
930 s = format (0, "%U: ", format_ip4_address, &addr);
932 range = (port_range_t *) rwh;
934 for (i = 0; i < srm->ranges_per_adjacency; i++)
936 for (j = 0; j < 8; j++)
938 if (range->low.as_u16[j])
939 s = format (s, "%d - %d ", (u32) range->low.as_u16[j],
940 (u32) range->hi.as_u16[j]);
944 vlib_cli_output (vm, "%s", s);
951 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
952 .path = "show ip source-and-port-range-check",
953 .function = show_source_and_port_range_check_fn,
955 "show ip source-and-port-range-check vrf <nn> <ip-addr> <port>",