FD.io VPP  v16.06
Vector Packet Processing
ip4_source_check.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 /*
16  * ip/ip4_source_check.c: IP v4 check source address (unicast RPF check)
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vnet/ip/ip.h>
41 
42 typedef struct {
43  u8 packet_data[64];
45 
46 static u8 * format_ip4_source_check_trace (u8 * s, va_list * va)
47 {
48  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
49  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
51 
52  s = format (s, "%U",
54  t->packet_data, sizeof (t->packet_data));
55 
56  return s;
57 }
58 
59 typedef enum {
63 
64 typedef enum {
68 
69 typedef union {
70  struct {
71  u32 no_default_route : 1;
72  u32 fib_index : 31;
73  };
74  u32 as_u32[1];
76 
79  vlib_node_runtime_t * node,
80  vlib_frame_t * frame,
81  ip4_source_check_type_t source_check_type)
82 {
83  ip4_main_t * im = &ip4_main;
84  ip_lookup_main_t * lm = &im->lookup_main;
86  u32 n_left_from, * from, * to_next;
87  u32 next_index;
88  vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip4_input_node.index);
89 
90  from = vlib_frame_vector_args (frame);
91  n_left_from = frame->n_vectors;
92  next_index = node->cached_next_index;
93 
94  if (node->flags & VLIB_NODE_FLAG_TRACE)
95  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
96  /* stride */ 1,
97  sizeof (ip4_source_check_trace_t));
98 
99  while (n_left_from > 0)
100  {
101  u32 n_left_to_next;
102 
103  vlib_get_next_frame (vm, node, next_index,
104  to_next, n_left_to_next);
105 
106  while (n_left_from >= 4 && n_left_to_next >= 2)
107  {
108  vlib_buffer_t * p0, * p1;
109  ip4_header_t * ip0, * ip1;
110  ip4_fib_mtrie_t * mtrie0, * mtrie1;
111  ip4_fib_mtrie_leaf_t leaf0, leaf1;
112  ip4_source_check_config_t * c0, * c1;
113  ip_adjacency_t * adj0, * adj1;
114  u32 pi0, next0, pass0, adj_index0;
115  u32 pi1, next1, pass1, adj_index1;
116 
117  /* Prefetch next iteration. */
118  {
119  vlib_buffer_t * p2, * p3;
120 
121  p2 = vlib_get_buffer (vm, from[2]);
122  p3 = vlib_get_buffer (vm, from[3]);
123 
124  vlib_prefetch_buffer_header (p2, LOAD);
125  vlib_prefetch_buffer_header (p3, LOAD);
126 
127  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
128  CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
129  }
130 
131  pi0 = to_next[0] = from[0];
132  pi1 = to_next[1] = from[1];
133  from += 2;
134  to_next += 2;
135  n_left_from -= 2;
136  n_left_to_next -= 2;
137 
138  p0 = vlib_get_buffer (vm, pi0);
139  p1 = vlib_get_buffer (vm, pi1);
140 
141  ip0 = vlib_buffer_get_current (p0);
142  ip1 = vlib_buffer_get_current (p1);
143 
145  &vnet_buffer (p0)->ip.current_config_index,
146  &next0,
147  sizeof (c0[0]));
149  &vnet_buffer (p1)->ip.current_config_index,
150  &next1,
151  sizeof (c1[0]));
152 
153  mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
154  mtrie1 = &vec_elt_at_index (im->fibs, c1->fib_index)->mtrie;
155 
156  leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
157 
158  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
159  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
160 
161  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
162  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
163 
164  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
165  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
166 
167  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
168  leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
169 
170  adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
171  adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
172 
173  ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
174  &ip0->src_address,
175  c0->no_default_route));
176  ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, c1->fib_index,
177  &ip1->src_address,
178  c1->no_default_route));
179 
180  adj0 = ip_get_adjacency (lm, adj_index0);
181  adj1 = ip_get_adjacency (lm, adj_index1);
182 
183  /* Pass multicast. */
184  pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
185  pass1 = ip4_address_is_multicast (&ip1->src_address) || ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
186 
187  pass0 |= (adj0->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
188  && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
189  || vnet_buffer (p0)->sw_if_index[VLIB_RX] == adj0->rewrite_header.sw_if_index));
190  pass1 |= (adj1->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
191  && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
192  || vnet_buffer (p1)->sw_if_index[VLIB_RX] == adj1->rewrite_header.sw_if_index));
193 
194  next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
195  next1 = (pass1 ? next1 : IP4_SOURCE_CHECK_NEXT_DROP);
196 
197  p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
198  p1->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
199 
200  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
201  to_next, n_left_to_next,
202  pi0, pi1, next0, next1);
203  }
204 
205  while (n_left_from > 0 && n_left_to_next > 0)
206  {
207  vlib_buffer_t * p0;
208  ip4_header_t * ip0;
209  ip4_fib_mtrie_t * mtrie0;
210  ip4_fib_mtrie_leaf_t leaf0;
212  ip_adjacency_t * adj0;
213  u32 pi0, next0, pass0, adj_index0;
214 
215  pi0 = from[0];
216  to_next[0] = pi0;
217  from += 1;
218  to_next += 1;
219  n_left_from -= 1;
220  n_left_to_next -= 1;
221 
222  p0 = vlib_get_buffer (vm, pi0);
223  ip0 = vlib_buffer_get_current (p0);
224 
226  &vnet_buffer (p0)->ip.current_config_index,
227  &next0,
228  sizeof (c0[0]));
229 
230  mtrie0 = &vec_elt_at_index (im->fibs, c0->fib_index)->mtrie;
231 
232  leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
233 
234  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
235 
236  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
237 
238  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
239 
240  leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
241 
242  adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
243 
244  ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, c0->fib_index,
245  &ip0->src_address,
246  c0->no_default_route));
247  adj0 = ip_get_adjacency (lm, adj_index0);
248 
249  /* Pass multicast. */
250  pass0 = ip4_address_is_multicast (&ip0->src_address) || ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
251 
252  pass0 |= (adj0->lookup_next_index == IP_LOOKUP_NEXT_REWRITE
253  && (source_check_type == IP4_SOURCE_CHECK_REACHABLE_VIA_ANY
254  || vnet_buffer (p0)->sw_if_index[VLIB_RX] == adj0->rewrite_header.sw_if_index));
255 
256  next0 = (pass0 ? next0 : IP4_SOURCE_CHECK_NEXT_DROP);
257  p0->error = error_node->errors[IP4_ERROR_UNICAST_SOURCE_CHECK_FAILS];
258 
259  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
260  to_next, n_left_to_next,
261  pi0, next0);
262  }
263 
264  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
265  }
266 
267  return frame->n_vectors;
268 }
269 
270 static uword
272  vlib_node_runtime_t * node,
273  vlib_frame_t * frame)
274 {
276 }
277 
278 static uword
280  vlib_node_runtime_t * node,
281  vlib_frame_t * frame)
282 {
284 }
285 
288  .name = "ip4-source-check-via-any",
289  .vector_size = sizeof (u32),
290 
291  .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
292  .next_nodes = {
293  [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
294  },
295 
296  .format_buffer = format_ip4_header,
297  .format_trace = format_ip4_source_check_trace,
298 };
299 
302  .name = "ip4-source-check-via-rx",
303  .vector_size = sizeof (u32),
304 
305  .n_next_nodes = IP4_SOURCE_CHECK_N_NEXT,
306  .next_nodes = {
307  [IP4_SOURCE_CHECK_NEXT_DROP] = "error-drop",
308  },
309 
310  .format_buffer = format_ip4_header,
311  .format_trace = format_ip4_source_check_trace,
312 };
313 
314 static clib_error_t *
316  unformat_input_t * input,
317  vlib_cli_command_t * cmd)
318 {
319  vnet_main_t * vnm = vnet_get_main();
320  ip4_main_t * im = &ip4_main;
321  ip_lookup_main_t * lm = &im->lookup_main;
323  clib_error_t * error = 0;
324  u32 sw_if_index, is_del, ci;
327 
328  sw_if_index = ~0;
329 
330  if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
331  {
332  error = clib_error_return (0, "unknown interface `%U'",
333  format_unformat_error, input);
334  goto done;
335  }
336 
337  is_del = 0;
338  config.no_default_route = 0;
339  config.fib_index = im->fib_index_by_sw_if_index[sw_if_index];
341  if (unformat (input, "del"))
342  is_del = 1;
343 
344  ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
345  ci = (is_del
348  (vm, &rx_cm->config_main,
349  ci,
350  type,
351  &config,
352  sizeof (config));
353  rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
354 
355  done:
356  return error;
357 }
358 
359 VLIB_CLI_COMMAND (set_interface_ip_source_check_command, static) = {
360  .path = "set interface ip source-check",
361  .function = set_ip_source_check,
362  .short_help = "Set IP4/IP6 interface unicast source check",
363 };
364 
365 /* Dummy init function to get us linked in. */
367 { return 0; }
368 
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Definition: main.c:459
always_inline 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
always_inline uword ip4_address_is_multicast(ip4_address_t *a)
Definition: ip4_packet.h:263
#define CLIB_UNUSED(x)
Definition: clib.h:79
u32 * config_index_by_sw_if_index
Definition: lookup.h:345
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
always_inline uword ip4_source_check_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip4_source_check_type_t source_check_type)
ip4_address_t src_address
Definition: ip4_packet.h:138
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
ip_lookup_next_t lookup_next_index
Definition: lookup.h:163
always_inline u32 ip4_fib_mtrie_leaf_get_adj_index(ip4_fib_mtrie_leaf_t n)
Definition: ip4_mtrie.h:66
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:284
ip_config_main_t rx_config_mains[VNET_N_CAST]
Definition: lookup.h:401
ip_lookup_main_t lookup_main
Definition: ip4.h:129
u32 * fib_index_by_sw_if_index
Definition: ip4.h:137
unformat_function_t unformat_vnet_sw_interface
vlib_error_t * errors
Definition: node.h:378
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
static clib_error_t * set_ip_source_check(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
#define always_inline
Definition: clib.h:84
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:50
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:953
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
static uword ip4_source_check_reachable_via_rx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip4_source_check_next_t
vlib_node_registration_t ip4_input_node
(constructor) VLIB_REGISTER_NODE (ip4_input_node)
Definition: ip4_input.c:353
vlib_node_registration_t ip4_check_source_reachable_via_rx
(constructor) VLIB_REGISTER_NODE (ip4_check_source_reachable_via_rx)
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Definition: buffer_node.h:43
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Definition: buffer_node.h:83
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Definition: node_funcs.h:265
ip4_rx_feature_type_t
Definition: ip4.h:104
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:129
u16 n_vectors
Definition: node.h:307
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
clib_error_t * ip4_source_check_init(vlib_main_t *vm)
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
u16 cached_next_index
Definition: node.h:422
#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
ip4_fib_t * fibs
Definition: ip4.h:132
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
#define vnet_buffer(b)
Definition: buffer.h:300
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:225
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:233
always_inline ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:423
u64 uword
Definition: types.h:112
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:45
unsigned char u8
Definition: types.h:56
ip4_source_check_type_t
static uword ip4_source_check_reachable_via_any(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:162
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
ip4_main_t ip4_main
Definition: ip4_forward.c:1394
always_inline vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:61
u8 data[0]
Packet data.
Definition: buffer.h:150
vlib_node_registration_t ip4_check_source_reachable_via_any
(constructor) VLIB_REGISTER_NODE (ip4_check_source_reachable_via_any)
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
always_inline void * vnet_get_config_data(vnet_config_main_t *cm, u32 *config_index, u32 *next_index, u32 n_data_bytes)
Definition: config.h:115
static u8 * format_ip4_source_check_trace(u8 *s, va_list *va)
always_inline 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:343
Definition: defs.h:45