32a2ab760ff8d099e322b16200c04e4e9b477e9c
[vpp.git] / src / vnet / ip / ip6_punt_drop.c
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 #include <vnet/ip/ip.h>
17 #include <vnet/ip/ip_punt_drop.h>
18 #include <vnet/policer/policer.h>
19 #include <vnet/policer/police_inlines.h>
20
21 /* *INDENT-OFF* */
22 VNET_FEATURE_ARC_INIT (ip6_punt) =
23 {
24   .arc_name  = "ip6-punt",
25   .start_nodes = VNET_FEATURES ("ip6-punt"),
26 };
27
28 VNET_FEATURE_ARC_INIT (ip6_drop) =
29 {
30   .arc_name  = "ip6-drop",
31   .start_nodes = VNET_FEATURES ("ip6-drop", "ip6-not-enabled"),
32 };
33 /* *INDENT-ON* */
34
35 extern ip_punt_policer_t ip6_punt_policer_cfg;
36
37 #ifndef CLIB_MARCH_VARIANT
38 ip_punt_policer_t ip6_punt_policer_cfg;
39 #endif /* CLIB_MARCH_VARIANT */
40
41 static char *ip6_punt_policer_handoff_error_strings[] = { "congestion drop" };
42
43 VLIB_NODE_FN (ip6_punt_policer_handoff_node)
44 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
45 {
46   return policer_handoff (vm, node, frame, ip6_punt_policer_cfg.fq_index,
47                           ip6_punt_policer_cfg.policer_index);
48 }
49
50 VLIB_REGISTER_NODE (ip6_punt_policer_handoff_node) = {
51   .name = "ip6-punt-policer-handoff",
52   .vector_size = sizeof (u32),
53   .format_trace = format_policer_handoff_trace,
54   .type = VLIB_NODE_TYPE_INTERNAL,
55   .n_errors = ARRAY_LEN(ip6_punt_policer_handoff_error_strings),
56   .error_strings = ip6_punt_policer_handoff_error_strings,
57
58   .n_next_nodes = 1,
59   .next_nodes = {
60     [0] = "error-drop",
61   },
62 };
63
64 static char *ip6_punt_policer_error_strings[] = {
65 #define _(sym,string) string,
66   foreach_ip_punt_policer_error
67 #undef _
68 };
69
70 VLIB_NODE_FN (ip6_punt_policer_node) (vlib_main_t * vm,
71                                       vlib_node_runtime_t * node,
72                                       vlib_frame_t * frame)
73 {
74   return (ip_punt_policer (vm, node, frame,
75                            vnet_feat_arc_ip6_punt.feature_arc_index,
76                            ip6_punt_policer_cfg.policer_index));
77 }
78
79
80 /* *INDENT-OFF* */
81
82 VLIB_REGISTER_NODE (ip6_punt_policer_node) = {
83   .name = "ip6-punt-policer",
84   .vector_size = sizeof (u32),
85   .n_next_nodes = IP_PUNT_POLICER_N_NEXT,
86   .format_trace = format_ip_punt_policer_trace,
87   .n_errors = ARRAY_LEN(ip6_punt_policer_error_strings),
88   .error_strings = ip6_punt_policer_error_strings,
89
90   /* edit / add dispositions here */
91   .next_nodes = {
92     [IP_PUNT_POLICER_NEXT_DROP] = "ip6-drop",
93     [IP_PUNT_POLICER_NEXT_HANDOFF] = "ip6-punt-policer-handoff",
94   },
95 };
96
97 VNET_FEATURE_INIT (ip6_punt_policer_node, static) = {
98   .arc_name = "ip6-punt",
99   .node_name = "ip6-punt-policer",
100   .runs_before = VNET_FEATURES("ip6-punt-redirect")
101 };
102 /* *INDENT-ON* */
103
104 VLIB_NODE_FN (ip6_drop_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
105                               vlib_frame_t * frame)
106 {
107   if (node->flags & VLIB_NODE_FLAG_TRACE)
108     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
109
110   return ip_drop_or_punt (vm, node, frame,
111                           vnet_feat_arc_ip6_drop.feature_arc_index);
112
113 }
114
115 VLIB_NODE_FN (ip6_not_enabled_node) (vlib_main_t * vm,
116                                      vlib_node_runtime_t * node,
117                                      vlib_frame_t * frame)
118 {
119   if (node->flags & VLIB_NODE_FLAG_TRACE)
120     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
121
122   return ip_drop_or_punt (vm, node, frame,
123                           vnet_feat_arc_ip6_drop.feature_arc_index);
124
125 }
126
127 VLIB_NODE_FN (ip6_punt_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
128                               vlib_frame_t * frame)
129 {
130   if (node->flags & VLIB_NODE_FLAG_TRACE)
131     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
132
133   return ip_drop_or_punt (vm, node, frame,
134                           vnet_feat_arc_ip6_punt.feature_arc_index);
135 }
136
137 /* *INDENT-OFF* */
138 VLIB_REGISTER_NODE (ip6_drop_node) =
139 {
140   .name = "ip6-drop",
141   .vector_size = sizeof (u32),
142   .format_trace = format_ip6_forward_next_trace,
143   .n_next_nodes = 1,
144   .next_nodes = {
145     [0] = "error-drop",
146   },
147 };
148
149 VLIB_REGISTER_NODE (ip6_not_enabled_node) = {
150   .name = "ip6-not-enabled",
151   .vector_size = sizeof (u32),
152   .format_trace = format_ip6_forward_next_trace,
153   .sibling_of = "ip6-drop",
154 };
155
156 VLIB_REGISTER_NODE (ip6_punt_node) =
157 {
158   .name = "ip6-punt",
159   .vector_size = sizeof (u32),
160   .format_trace = format_ip6_forward_next_trace,
161   .n_next_nodes = 1,
162   .next_nodes = {
163     [0] = "error-punt",
164   },
165 };
166
167 VNET_FEATURE_INIT (ip6_punt_end_of_arc, static) = {
168   .arc_name = "ip6-punt",
169   .node_name = "error-punt",
170   .runs_before = 0, /* not before any other features */
171 };
172
173 VNET_FEATURE_INIT (ip6_drop_end_of_arc, static) = {
174   .arc_name = "ip6-drop",
175   .node_name = "error-drop",
176   .runs_before = 0, /* not before any other features */
177 };
178 /* *INDENT-ON */
179
180 #ifndef CLIB_MARCH_VARIANT
181 void
182 ip6_punt_policer_add_del (u8 is_add, u32 policer_index)
183 {
184   ip6_punt_policer_cfg.policer_index = policer_index;
185
186   vnet_feature_enable_disable ("ip6-punt", "ip6-punt-policer",
187                                0, is_add, 0, 0);
188 }
189 #endif /* CLIB_MARCH_VARIANT */
190
191 static clib_error_t *
192 ip6_punt_police_cmd (vlib_main_t * vm,
193                      unformat_input_t * main_input,
194                      vlib_cli_command_t * cmd)
195 {
196   unformat_input_t _line_input, *line_input = &_line_input;
197   clib_error_t *error = 0;
198   u32 policer_index;
199   u8 is_add = 1;
200
201   policer_index = ~0;
202
203   if (!unformat_user (main_input, unformat_line_input, line_input))
204     return 0;
205
206   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
207     {
208       if (unformat (line_input, "%d", &policer_index))
209         ;
210       else if (unformat (line_input, "del"))
211         is_add = 0;
212       else if (unformat (line_input, "add"))
213         is_add = 1;
214       else
215         {
216           error = unformat_parse_error (line_input);
217           goto done;
218         }
219     }
220
221   if (is_add && ~0 == policer_index)
222   {
223       error = clib_error_return (0, "expected policer index `%U'",
224                                  format_unformat_error, line_input);
225       goto done;
226   }
227   if (!is_add)
228       policer_index = ~0;
229
230   ip6_punt_policer_add_del(is_add, policer_index);
231
232 done:
233   unformat_free (line_input);
234   return (error);
235 }
236
237 /*?
238  *
239  * @cliexpar
240  * @cliexcmd{set ip punt policer <INDEX>}
241  ?*/
242 /* *INDENT-OFF* */
243 VLIB_CLI_COMMAND (ip6_punt_policer_command, static) =
244 {
245   .path = "ip6 punt policer",
246   .function = ip6_punt_police_cmd,
247   .short_help = "ip6 punt policer [add|del] <index>",
248 };
249
250 /* *INDENT-ON* */
251
252 #define foreach_ip6_punt_redirect_error         \
253 _(DROP, "ip6 punt redirect drop")
254
255 typedef enum
256 {
257 #define _(sym,str) IP6_PUNT_REDIRECT_ERROR_##sym,
258   foreach_ip6_punt_redirect_error
259 #undef _
260     IP6_PUNT_REDIRECT_N_ERROR,
261 } ip6_punt_redirect_error_t;
262
263 static char *ip6_punt_redirect_error_strings[] = {
264 #define _(sym,string) string,
265   foreach_ip6_punt_redirect_error
266 #undef _
267 };
268
269 VLIB_NODE_FN (ip6_punt_redirect_node) (vlib_main_t * vm,
270                                        vlib_node_runtime_t * node,
271                                        vlib_frame_t * frame)
272 {
273   return (ip_punt_redirect (vm, node, frame,
274                             vnet_feat_arc_ip6_punt.feature_arc_index,
275                             FIB_PROTOCOL_IP6));
276 }
277
278 /* *INDENT-OFF* */
279 VLIB_REGISTER_NODE (ip6_punt_redirect_node) = {
280   .name = "ip6-punt-redirect",
281   .vector_size = sizeof (u32),
282   .n_next_nodes = IP_PUNT_REDIRECT_N_NEXT,
283   .format_trace = format_ip_punt_redirect_trace,
284   .n_errors = ARRAY_LEN(ip6_punt_redirect_error_strings),
285   .error_strings = ip6_punt_redirect_error_strings,
286
287   /* edit / add dispositions here */
288   .next_nodes = {
289     [IP_PUNT_REDIRECT_NEXT_DROP] = "ip6-drop",
290     [IP_PUNT_REDIRECT_NEXT_TX] = "ip6-rewrite",
291     [IP_PUNT_REDIRECT_NEXT_ARP] = "ip6-discover-neighbor",
292   },
293 };
294
295 VNET_FEATURE_INIT (ip6_punt_redirect_node, static) = {
296   .arc_name = "ip6-punt",
297   .node_name = "ip6-punt-redirect",
298   .runs_before = VNET_FEATURES("error-punt")
299 };
300 /* *INDENT-ON* */
301
302 #ifndef CLIB_MARCH_VARIANT
303
304 static u32 ip6_punt_redirect_enable_counts;
305
306 void
307 ip6_punt_redirect_add_paths (u32 rx_sw_if_index,
308                              const fib_route_path_t *rpaths)
309 {
310   ip_punt_redirect_add (FIB_PROTOCOL_IP6,
311                         rx_sw_if_index,
312                         FIB_FORW_CHAIN_TYPE_UNICAST_IP6, rpaths);
313
314   if (1 == ++ip6_punt_redirect_enable_counts)
315     vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 1, 0, 0);
316 }
317
318 void
319 ip6_punt_redirect_del (u32 rx_sw_if_index)
320 {
321   ASSERT (ip6_punt_redirect_enable_counts);
322   if (0 == --ip6_punt_redirect_enable_counts)
323     vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 0, 0, 0);
324
325   ip_punt_redirect_del (FIB_PROTOCOL_IP6, rx_sw_if_index);
326 }
327 #endif /* CLIB_MARCH_VARIANT */
328
329 static clib_error_t *
330 ip6_punt_redirect_cmd (vlib_main_t * vm,
331                        unformat_input_t * main_input,
332                        vlib_cli_command_t * cmd)
333 {
334   unformat_input_t _line_input, *line_input = &_line_input;
335   fib_route_path_t *rpaths = NULL, rpath;
336   dpo_proto_t payload_proto = DPO_PROTO_IP6;
337   clib_error_t *error = 0;
338   u32 rx_sw_if_index = ~0;
339   vnet_main_t *vnm;
340   u8 is_add;
341
342   is_add = 1;
343   vnm = vnet_get_main ();
344
345   if (!unformat_user (main_input, unformat_line_input, line_input))
346     return 0;
347
348   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
349     {
350       if (unformat (line_input, "del"))
351         is_add = 0;
352       else if (unformat (line_input, "add"))
353         is_add = 1;
354       else if (unformat (line_input, "rx all"))
355         rx_sw_if_index = 0;
356       else if (unformat (line_input, "rx %U",
357                          unformat_vnet_sw_interface, vnm, &rx_sw_if_index))
358         ;
359       else if (unformat (line_input, "via %U",
360                          unformat_fib_route_path, &rpath, &payload_proto))
361         vec_add1 (rpaths, rpath);
362       else
363         {
364           error = unformat_parse_error (line_input);
365           goto done;
366         }
367     }
368
369   if (~0 == rx_sw_if_index)
370     {
371       error = unformat_parse_error (line_input);
372       goto done;
373     }
374
375   if (is_add)
376     {
377       if (vec_len (rpaths))
378         ip6_punt_redirect_add_paths (rx_sw_if_index, rpaths);
379     }
380   else
381     {
382       ip6_punt_redirect_del (rx_sw_if_index);
383     }
384
385 done:
386   vec_free (rpaths);
387   unformat_free (line_input);
388   return (error);
389 }
390
391 /*?
392  *
393  * @cliexpar
394  * @cliexcmd{set ip punt policer <INDEX>}
395  ?*/
396 /* *INDENT-OFF* */
397 VLIB_CLI_COMMAND (ip6_punt_redirect_command, static) =
398 {
399   .path = "ip6 punt redirect",
400   .function = ip6_punt_redirect_cmd,
401   .short_help = "ip6 punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
402 };
403 /* *INDENT-ON* */
404
405 #ifndef CLIB_MARCH_VARIANT
406
407 #endif /* CLIB_MARCH_VARIANT */
408
409 static clib_error_t *
410 ip6_punt_redirect_show_cmd (vlib_main_t * vm,
411                             unformat_input_t * main_input,
412                             vlib_cli_command_t * cmd)
413 {
414   vlib_cli_output (vm, "%U", format_ip_punt_redirect, FIB_PROTOCOL_IP6);
415
416   return (NULL);
417 }
418
419 /*?
420  *
421  * @cliexpar
422  * @cliexcmd{set ip punt policer <INDEX>}
423  ?*/
424 /* *INDENT-OFF* */
425 VLIB_CLI_COMMAND (show_ip6_punt_redirect_command, static) =
426 {
427   .path = "show ip6 punt redirect",
428   .function = ip6_punt_redirect_show_cmd,
429   .short_help = "show ip6 punt redirect",
430   .is_mp_safe = 1,
431 };
432 /* *INDENT-ON* */
433
434 /*
435  * fd.io coding-style-patch-verification: ON
436  *
437  * Local Variables:
438  * eval: (c-set-style "gnu")
439  * End:
440  */