Line data Source code
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 : #ifndef __IP_PUNT_DROP_H__
17 : #define __IP_PUNT_DROP_H__
18 :
19 : #include <vnet/ip/ip.h>
20 : #include <vnet/policer/policer.h>
21 : #include <vnet/policer/police_inlines.h>
22 :
23 : /**
24 : * IP4 punt policer configuration
25 : * we police the punt rate to prevent overloading the host
26 : */
27 : typedef struct ip_punt_policer_t_
28 : {
29 : u32 policer_index;
30 : u32 fq_index;
31 : } ip_punt_policer_t;
32 :
33 : typedef enum ip_punt_policer_next_t_
34 : {
35 : IP_PUNT_POLICER_NEXT_DROP,
36 : IP_PUNT_POLICER_NEXT_HANDOFF,
37 : IP_PUNT_POLICER_N_NEXT,
38 : } ip_punt_policer_next_t;
39 :
40 : typedef struct ip_punt_policer_trace_t_
41 : {
42 : u32 policer_index;
43 : u32 next;
44 : } ip_punt_policer_trace_t;
45 :
46 : #define foreach_ip_punt_policer_error \
47 : _(DROP, "ip punt policer drop")
48 :
49 : typedef enum
50 : {
51 : #define _(sym,str) IP_PUNT_POLICER_ERROR_##sym,
52 : foreach_ip_punt_policer_error
53 : #undef _
54 : IP4_PUNT_POLICER_N_ERROR,
55 : } ip_punt_policer_error_t;
56 :
57 : extern u8 *format_ip_punt_policer_trace (u8 * s, va_list * args);
58 : extern vlib_node_registration_t ip4_punt_policer_node;
59 : extern ip_punt_policer_t ip4_punt_policer_cfg;
60 : extern vlib_node_registration_t ip6_punt_policer_node;
61 : extern ip_punt_policer_t ip6_punt_policer_cfg;
62 :
63 : /**
64 : * IP punt policing node function
65 : */
66 : always_inline uword
67 33 : ip_punt_policer (vlib_main_t * vm,
68 : vlib_node_runtime_t * node,
69 : vlib_frame_t * frame, u8 arc_index, u32 policer_index)
70 : {
71 : u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
72 : u64 time_in_policer_periods;
73 33 : vnet_feature_main_t *fm = &feature_main;
74 33 : vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
75 :
76 33 : time_in_policer_periods =
77 33 : clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
78 :
79 33 : from = vlib_frame_vector_args (frame);
80 33 : n_left_from = frame->n_vectors;
81 33 : next_index = node->cached_next_index;
82 :
83 66 : while (n_left_from > 0)
84 : {
85 33 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
86 :
87 2133 : while (n_left_from >= 4 && n_left_to_next >= 2)
88 : {
89 : vlib_buffer_t *b0, *b1;
90 : u32 next0, next1;
91 : u8 act0, act1;
92 : u32 bi0, bi1;
93 :
94 2100 : next0 = next1 = 0;
95 2100 : bi0 = to_next[0] = from[0];
96 2100 : bi1 = to_next[1] = from[1];
97 :
98 2100 : from += 2;
99 2100 : n_left_from -= 2;
100 2100 : to_next += 2;
101 2100 : n_left_to_next -= 2;
102 :
103 2100 : b0 = vlib_get_buffer (vm, bi0);
104 2100 : b1 = vlib_get_buffer (vm, bi1);
105 :
106 2100 : act0 = vnet_policer_police (vm, b0, policer_index,
107 : time_in_policer_periods, POLICE_CONFORM,
108 : true);
109 2100 : act1 = vnet_policer_police (vm, b1, policer_index,
110 : time_in_policer_periods, POLICE_CONFORM,
111 : true);
112 :
113 2100 : if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
114 : {
115 192 : next0 = next1 = IP_PUNT_POLICER_NEXT_HANDOFF;
116 : }
117 : else
118 : {
119 :
120 1908 : vnet_get_config_data (&cm->config_main,
121 : &b0->current_config_index, &next0, 0);
122 1908 : vnet_get_config_data (&cm->config_main,
123 : &b1->current_config_index, &next1, 0);
124 :
125 1908 : if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
126 : {
127 1495 : next0 = IP_PUNT_POLICER_NEXT_DROP;
128 1495 : b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
129 : }
130 1908 : if (PREDICT_FALSE (act1 == QOS_ACTION_DROP))
131 : {
132 1499 : next1 = IP_PUNT_POLICER_NEXT_DROP;
133 1499 : b1->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
134 : }
135 :
136 1908 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
137 : {
138 : ip_punt_policer_trace_t *t =
139 1875 : vlib_add_trace (vm, node, b0, sizeof (*t));
140 1875 : t->next = next0;
141 1875 : t->policer_index = policer_index;
142 : }
143 1908 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
144 : {
145 : ip_punt_policer_trace_t *t =
146 1875 : vlib_add_trace (vm, node, b1, sizeof (*t));
147 1875 : t->next = next1;
148 1875 : t->policer_index = policer_index;
149 : }
150 : }
151 :
152 2100 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
153 : n_left_to_next,
154 : bi0, bi1, next0, next1);
155 : }
156 114 : while (n_left_from > 0 && n_left_to_next > 0)
157 : {
158 : vlib_buffer_t *b0;
159 : u32 next0;
160 : u32 bi0;
161 : u8 act0;
162 :
163 81 : next0 = 0;
164 81 : bi0 = to_next[0] = from[0];
165 :
166 81 : from += 1;
167 81 : n_left_from -= 1;
168 81 : to_next += 1;
169 81 : n_left_to_next -= 1;
170 :
171 81 : b0 = vlib_get_buffer (vm, bi0);
172 :
173 81 : act0 = vnet_policer_police (vm, b0, policer_index,
174 : time_in_policer_periods, POLICE_CONFORM,
175 : true);
176 81 : if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
177 : {
178 18 : next0 = IP_PUNT_POLICER_NEXT_HANDOFF;
179 : }
180 : else
181 : {
182 63 : vnet_get_config_data (&cm->config_main,
183 : &b0->current_config_index, &next0, 0);
184 :
185 63 : if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
186 : {
187 26 : next0 = IP_PUNT_POLICER_NEXT_DROP;
188 26 : b0->error = node->errors[IP_PUNT_POLICER_ERROR_DROP];
189 : }
190 :
191 63 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
192 : {
193 : ip_punt_policer_trace_t *t =
194 54 : vlib_add_trace (vm, node, b0, sizeof (*t));
195 54 : t->next = next0;
196 54 : t->policer_index = policer_index;
197 : }
198 : }
199 81 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
200 : n_left_to_next, bi0, next0);
201 : }
202 33 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
203 : }
204 :
205 33 : return frame->n_vectors;
206 : }
207 :
208 : /**
209 : * IP4 punt redirect per-rx interface configuration
210 : * redirect punted traffic to another location.
211 : */
212 : typedef struct ip_punt_redirect_rx_t_
213 : {
214 : /**
215 : * Node linkage into the FIB graph
216 : */
217 : fib_node_t node;
218 :
219 : fib_protocol_t fproto;
220 : fib_forward_chain_type_t payload_type;
221 : fib_node_index_t pl;
222 : u32 sibling;
223 :
224 : /**
225 : * redirect forwarding
226 : */
227 : dpo_id_t dpo;
228 : } ip_punt_redirect_rx_t;
229 :
230 : /**
231 : * IP punt redirect configuration
232 : */
233 : typedef struct ip_punt_redirect_t_
234 : {
235 : ip_punt_redirect_rx_t *pool;
236 :
237 : /**
238 : * per-RX interface configuration.
239 : * sw_if_index = 0 (from which packets are never received) is used to
240 : * indicate 'from-any'
241 : */
242 : index_t *redirect_by_rx_sw_if_index[FIB_PROTOCOL_IP_MAX];
243 : } ip_punt_redirect_cfg_t;
244 :
245 : extern ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
246 :
247 : /**
248 : * IP punt redirect next nodes
249 : */
250 : typedef enum ip_punt_redirect_next_t_
251 : {
252 : IP_PUNT_REDIRECT_NEXT_DROP,
253 : IP_PUNT_REDIRECT_NEXT_TX,
254 : IP_PUNT_REDIRECT_NEXT_ARP,
255 : IP_PUNT_REDIRECT_N_NEXT,
256 : } ip_punt_redirect_next_t;
257 :
258 : /**
259 : * IP Punt redirect trace
260 : */
261 : typedef struct ip4_punt_redirect_trace_t_
262 : {
263 : index_t rrxi;
264 : u32 next;
265 : } ip_punt_redirect_trace_t;
266 :
267 : /**
268 : * Add a punt redirect entry
269 : */
270 : extern void ip_punt_redirect_add (fib_protocol_t fproto, u32 rx_sw_if_index,
271 : fib_forward_chain_type_t ct,
272 : const fib_route_path_t *rpaths);
273 :
274 : extern void ip_punt_redirect_del (fib_protocol_t fproto, u32 rx_sw_if_index);
275 : extern index_t ip_punt_redirect_find (fib_protocol_t fproto,
276 : u32 rx_sw_if_index);
277 : extern u8 *format_ip_punt_redirect (u8 * s, va_list * args);
278 :
279 : extern u8 *format_ip_punt_redirect_trace (u8 * s, va_list * args);
280 :
281 : typedef walk_rc_t (*ip_punt_redirect_walk_cb_t) (u32 rx_sw_if_index,
282 : const ip_punt_redirect_rx_t *
283 : redirect, void *arg);
284 : extern void ip_punt_redirect_walk (fib_protocol_t fproto,
285 : ip_punt_redirect_walk_cb_t cb, void *ctx);
286 :
287 : static_always_inline ip_punt_redirect_rx_t *
288 10346 : ip_punt_redirect_get (index_t rrxi)
289 : {
290 10346 : return (pool_elt_at_index (ip_punt_redirect_cfg.pool, rrxi));
291 : }
292 :
293 : always_inline uword
294 94 : ip_punt_redirect (vlib_main_t * vm,
295 : vlib_node_runtime_t * node,
296 : vlib_frame_t * frame, u8 arc_index, fib_protocol_t fproto)
297 : {
298 : u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
299 94 : vnet_feature_main_t *fm = &feature_main;
300 94 : vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
301 : index_t *redirects;
302 :
303 94 : from = vlib_frame_vector_args (frame);
304 94 : n_left_from = frame->n_vectors;
305 94 : next_index = node->cached_next_index;
306 94 : redirects = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
307 :
308 188 : while (n_left_from > 0)
309 : {
310 94 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
311 :
312 10308 : while (n_left_from > 0 && n_left_to_next > 0)
313 : {
314 : u32 rx_sw_if_index0, rrxi0;
315 : ip_punt_redirect_rx_t *rrx0;
316 : vlib_buffer_t *b0;
317 : u32 next0;
318 : u32 bi0;
319 :
320 10214 : rrxi0 = INDEX_INVALID;
321 10214 : next0 = 0;
322 10214 : bi0 = to_next[0] = from[0];
323 :
324 10214 : from += 1;
325 10214 : n_left_from -= 1;
326 10214 : to_next += 1;
327 10214 : n_left_to_next -= 1;
328 :
329 10214 : b0 = vlib_get_buffer (vm, bi0);
330 :
331 10214 : vnet_get_config_data (&cm->config_main,
332 : &b0->current_config_index, &next0, 0);
333 :
334 10214 : rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
335 :
336 : /*
337 : * If config exists for this particular RX interface use it,
338 : * else use the default (at RX = 0)
339 : */
340 10214 : if (vec_len (redirects) > rx_sw_if_index0)
341 : {
342 10214 : rrxi0 = redirects[rx_sw_if_index0];
343 10214 : if (INDEX_INVALID == rrxi0)
344 3075 : rrxi0 = redirects[0];
345 : }
346 0 : else if (vec_len (redirects) >= 1)
347 0 : rrxi0 = redirects[0];
348 :
349 10214 : if (PREDICT_TRUE (INDEX_INVALID != rrxi0))
350 : {
351 : /* prevent ttl decrement on forward */
352 10214 : b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
353 10214 : rrx0 = ip_punt_redirect_get (rrxi0);
354 10214 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = rrx0->dpo.dpoi_index;
355 10214 : next0 = rrx0->dpo.dpoi_next_node;
356 : }
357 :
358 10214 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
359 : {
360 : ip_punt_redirect_trace_t *t =
361 9988 : vlib_add_trace (vm, node, b0, sizeof (*t));
362 9988 : t->next = next0;
363 9988 : t->rrxi = rrxi0;
364 : }
365 :
366 10214 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
367 : n_left_to_next, bi0, next0);
368 : }
369 :
370 94 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
371 : }
372 :
373 94 : return frame->n_vectors;
374 : }
375 :
376 : always_inline uword
377 2750 : ip_drop_or_punt (vlib_main_t * vm,
378 : vlib_node_runtime_t * node,
379 : vlib_frame_t * frame, u8 arc_index)
380 : {
381 : u32 *from, *to_next, n_left_from, n_left_to_next, next_index;
382 :
383 2750 : from = vlib_frame_vector_args (frame);
384 2750 : n_left_from = frame->n_vectors;
385 2750 : next_index = node->cached_next_index;
386 :
387 5500 : while (n_left_from > 0)
388 : {
389 2750 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
390 :
391 13083 : while (n_left_from >= 8 && n_left_to_next >= 4)
392 : {
393 : vlib_buffer_t *b0, *b1, *b2, *b3;
394 : u32 next0, next1, next2, next3;
395 : u32 bi0, bi1, bi2, bi3;
396 :
397 10333 : next0 = next1 = next2 = next3 = 0;
398 :
399 : /* Prefetch next iteration. */
400 : {
401 : vlib_buffer_t *p4, *p5, *p6, *p7;
402 :
403 10333 : p4 = vlib_get_buffer (vm, from[4]);
404 10333 : p5 = vlib_get_buffer (vm, from[5]);
405 10333 : p6 = vlib_get_buffer (vm, from[6]);
406 10333 : p7 = vlib_get_buffer (vm, from[7]);
407 :
408 10333 : vlib_prefetch_buffer_header (p4, LOAD);
409 10333 : vlib_prefetch_buffer_header (p5, LOAD);
410 10333 : vlib_prefetch_buffer_header (p6, LOAD);
411 10333 : vlib_prefetch_buffer_header (p7, LOAD);
412 : }
413 :
414 10333 : bi0 = to_next[0] = from[0];
415 10333 : bi1 = to_next[1] = from[1];
416 10333 : bi2 = to_next[2] = from[2];
417 10333 : bi3 = to_next[3] = from[3];
418 :
419 10333 : from += 4;
420 10333 : n_left_from -= 4;
421 10333 : to_next += 4;
422 10333 : n_left_to_next -= 4;
423 :
424 10333 : b0 = vlib_get_buffer (vm, bi0);
425 10333 : b1 = vlib_get_buffer (vm, bi1);
426 10333 : b2 = vlib_get_buffer (vm, bi2);
427 10333 : b3 = vlib_get_buffer (vm, bi3);
428 :
429 : /* punt and drop features are not associated with a given interface
430 : * so the special index 0 is used */
431 10333 : vnet_feature_arc_start (arc_index, 0, &next0, b0);
432 10333 : vnet_feature_arc_start (arc_index, 0, &next1, b1);
433 10333 : vnet_feature_arc_start (arc_index, 0, &next2, b2);
434 10333 : vnet_feature_arc_start (arc_index, 0, &next3, b3);
435 :
436 10333 : vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
437 : to_next, n_left_to_next,
438 : bi0, bi1, bi2, bi3,
439 : next0, next1, next2, next3);
440 : }
441 :
442 9394 : while (n_left_from > 0 && n_left_to_next > 0)
443 : {
444 : vlib_buffer_t *b0;
445 : u32 next0;
446 : u32 bi0;
447 :
448 6644 : next0 = 0;
449 6644 : bi0 = to_next[0] = from[0];
450 :
451 6644 : from += 1;
452 6644 : n_left_from -= 1;
453 6644 : to_next += 1;
454 6644 : n_left_to_next -= 1;
455 :
456 6644 : b0 = vlib_get_buffer (vm, bi0);
457 :
458 6644 : vnet_feature_arc_start (arc_index, 0, &next0, b0);
459 :
460 6644 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
461 : n_left_to_next, bi0, next0);
462 : }
463 2750 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
464 : }
465 :
466 2750 : return frame->n_vectors;
467 : }
468 :
469 : #endif
470 :
471 : /*
472 : * fd.io coding-style-patch-verification: ON
473 : *
474 : * Local Variables:
475 : * eval: (c-set-style "gnu")
476 : * End:
477 : */
|