ip: punt redirect add nh in api
[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 {
151   .name = "ip6-not-enabled",
152   .vector_size = sizeof (u32),
153   .format_trace = format_ip6_forward_next_trace,
154   .n_next_nodes = 1,
155   .next_nodes = {
156     [0] = "error-drop",
157   },
158 };
159
160 VLIB_REGISTER_NODE (ip6_punt_node) =
161 {
162   .name = "ip6-punt",
163   .vector_size = sizeof (u32),
164   .format_trace = format_ip6_forward_next_trace,
165   .n_next_nodes = 1,
166   .next_nodes = {
167     [0] = "error-punt",
168   },
169 };
170
171 VNET_FEATURE_INIT (ip6_punt_end_of_arc, static) = {
172   .arc_name = "ip6-punt",
173   .node_name = "error-punt",
174   .runs_before = 0, /* not before any other features */
175 };
176
177 VNET_FEATURE_INIT (ip6_drop_end_of_arc, static) = {
178   .arc_name = "ip6-drop",
179   .node_name = "error-drop",
180   .runs_before = 0, /* not before any other features */
181 };
182 /* *INDENT-ON */
183
184 #ifndef CLIB_MARCH_VARIANT
185 void
186 ip6_punt_policer_add_del (u8 is_add, u32 policer_index)
187 {
188   ip6_punt_policer_cfg.policer_index = policer_index;
189
190   vnet_feature_enable_disable ("ip6-punt", "ip6-punt-policer",
191                                0, is_add, 0, 0);
192 }
193 #endif /* CLIB_MARCH_VARIANT */
194
195 static clib_error_t *
196 ip6_punt_police_cmd (vlib_main_t * vm,
197                      unformat_input_t * main_input,
198                      vlib_cli_command_t * cmd)
199 {
200   unformat_input_t _line_input, *line_input = &_line_input;
201   clib_error_t *error = 0;
202   u32 policer_index;
203   u8 is_add = 1;
204
205   policer_index = ~0;
206
207   if (!unformat_user (main_input, unformat_line_input, line_input))
208     return 0;
209
210   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
211     {
212       if (unformat (line_input, "%d", &policer_index))
213         ;
214       else if (unformat (line_input, "del"))
215         is_add = 0;
216       else if (unformat (line_input, "add"))
217         is_add = 1;
218       else
219         {
220           error = unformat_parse_error (line_input);
221           goto done;
222         }
223     }
224
225   if (is_add && ~0 == policer_index)
226   {
227       error = clib_error_return (0, "expected policer index `%U'",
228                                  format_unformat_error, line_input);
229       goto done;
230   }
231   if (!is_add)
232       policer_index = ~0;
233
234   ip6_punt_policer_add_del(is_add, policer_index);
235
236 done:
237   unformat_free (line_input);
238   return (error);
239 }
240
241 /*?
242  *
243  * @cliexpar
244  * @cliexcmd{set ip punt policer <INDEX>}
245  ?*/
246 /* *INDENT-OFF* */
247 VLIB_CLI_COMMAND (ip6_punt_policer_command, static) =
248 {
249   .path = "ip6 punt policer",
250   .function = ip6_punt_police_cmd,
251   .short_help = "ip6 punt policer [add|del] <index>",
252 };
253
254 /* *INDENT-ON* */
255
256 #define foreach_ip6_punt_redirect_error         \
257 _(DROP, "ip6 punt redirect drop")
258
259 typedef enum
260 {
261 #define _(sym,str) IP6_PUNT_REDIRECT_ERROR_##sym,
262   foreach_ip6_punt_redirect_error
263 #undef _
264     IP6_PUNT_REDIRECT_N_ERROR,
265 } ip6_punt_redirect_error_t;
266
267 static char *ip6_punt_redirect_error_strings[] = {
268 #define _(sym,string) string,
269   foreach_ip6_punt_redirect_error
270 #undef _
271 };
272
273 VLIB_NODE_FN (ip6_punt_redirect_node) (vlib_main_t * vm,
274                                        vlib_node_runtime_t * node,
275                                        vlib_frame_t * frame)
276 {
277   return (ip_punt_redirect (vm, node, frame,
278                             vnet_feat_arc_ip6_punt.feature_arc_index,
279                             FIB_PROTOCOL_IP6));
280 }
281
282 /* *INDENT-OFF* */
283 VLIB_REGISTER_NODE (ip6_punt_redirect_node) = {
284   .name = "ip6-punt-redirect",
285   .vector_size = sizeof (u32),
286   .n_next_nodes = IP_PUNT_REDIRECT_N_NEXT,
287   .format_trace = format_ip_punt_redirect_trace,
288   .n_errors = ARRAY_LEN(ip6_punt_redirect_error_strings),
289   .error_strings = ip6_punt_redirect_error_strings,
290
291   /* edit / add dispositions here */
292   .next_nodes = {
293     [IP_PUNT_REDIRECT_NEXT_DROP] = "ip6-drop",
294     [IP_PUNT_REDIRECT_NEXT_TX] = "ip6-rewrite",
295     [IP_PUNT_REDIRECT_NEXT_ARP] = "ip6-discover-neighbor",
296   },
297 };
298
299 VNET_FEATURE_INIT (ip6_punt_redirect_node, static) = {
300   .arc_name = "ip6-punt",
301   .node_name = "ip6-punt-redirect",
302   .runs_before = VNET_FEATURES("error-punt")
303 };
304 /* *INDENT-ON* */
305
306 #ifndef CLIB_MARCH_VARIANT
307
308 void
309 ip6_punt_redirect_add_paths (u32 rx_sw_if_index,
310                              const fib_route_path_t *rpaths)
311 {
312   ip_punt_redirect_add (FIB_PROTOCOL_IP6,
313                         rx_sw_if_index,
314                         FIB_FORW_CHAIN_TYPE_UNICAST_IP6, rpaths);
315
316   vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 1, 0, 0);
317 }
318
319 void
320 ip6_punt_redirect_del (u32 rx_sw_if_index)
321 {
322   vnet_feature_enable_disable ("ip6-punt", "ip6-punt-redirect", 0, 0, 0, 0);
323
324   ip_punt_redirect_del (FIB_PROTOCOL_IP6, rx_sw_if_index);
325 }
326 #endif /* CLIB_MARCH_VARIANT */
327
328 static clib_error_t *
329 ip6_punt_redirect_cmd (vlib_main_t * vm,
330                        unformat_input_t * main_input,
331                        vlib_cli_command_t * cmd)
332 {
333   unformat_input_t _line_input, *line_input = &_line_input;
334   fib_route_path_t *rpaths = NULL, rpath;
335   dpo_proto_t payload_proto = DPO_PROTO_IP6;
336   clib_error_t *error = 0;
337   u32 rx_sw_if_index = ~0;
338   vnet_main_t *vnm;
339   u8 is_add;
340
341   is_add = 1;
342   vnm = vnet_get_main ();
343
344   if (!unformat_user (main_input, unformat_line_input, line_input))
345     return 0;
346
347   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
348     {
349       if (unformat (line_input, "del"))
350         is_add = 0;
351       else if (unformat (line_input, "add"))
352         is_add = 1;
353       else if (unformat (line_input, "rx all"))
354         rx_sw_if_index = 0;
355       else if (unformat (line_input, "rx %U",
356                          unformat_vnet_sw_interface, vnm, &rx_sw_if_index))
357         ;
358       else if (unformat (line_input, "via %U",
359                          unformat_fib_route_path, &rpath, &payload_proto))
360         vec_add1 (rpaths, rpath);
361       else
362         {
363           error = unformat_parse_error (line_input);
364           goto done;
365         }
366     }
367
368   if (~0 == rx_sw_if_index)
369     {
370       error = unformat_parse_error (line_input);
371       goto done;
372     }
373
374   if (is_add)
375     {
376       if (vec_len (rpaths))
377         ip6_punt_redirect_add_paths (rx_sw_if_index, rpaths);
378     }
379   else
380     {
381       ip6_punt_redirect_del (rx_sw_if_index);
382     }
383
384 done:
385   vec_free (rpaths);
386   unformat_free (line_input);
387   return (error);
388 }
389
390 /*?
391  *
392  * @cliexpar
393  * @cliexcmd{set ip punt policer <INDEX>}
394  ?*/
395 /* *INDENT-OFF* */
396 VLIB_CLI_COMMAND (ip6_punt_redirect_command, static) =
397 {
398   .path = "ip6 punt redirect",
399   .function = ip6_punt_redirect_cmd,
400   .short_help = "ip6 punt redirect [add|del] rx [<interface>|all] via [<nh>] <tx_interface>",
401 };
402 /* *INDENT-ON* */
403
404 #ifndef CLIB_MARCH_VARIANT
405
406 #endif /* CLIB_MARCH_VARIANT */
407
408 static clib_error_t *
409 ip6_punt_redirect_show_cmd (vlib_main_t * vm,
410                             unformat_input_t * main_input,
411                             vlib_cli_command_t * cmd)
412 {
413   vlib_cli_output (vm, "%U", format_ip_punt_redirect, FIB_PROTOCOL_IP6);
414
415   return (NULL);
416 }
417
418 /*?
419  *
420  * @cliexpar
421  * @cliexcmd{set ip punt policer <INDEX>}
422  ?*/
423 /* *INDENT-OFF* */
424 VLIB_CLI_COMMAND (show_ip6_punt_redirect_command, static) =
425 {
426   .path = "show ip6 punt redirect",
427   .function = ip6_punt_redirect_show_cmd,
428   .short_help = "show ip6 punt redirect",
429   .is_mp_safe = 1,
430 };
431 /* *INDENT-ON* */
432
433 /*
434  * fd.io coding-style-patch-verification: ON
435  *
436  * Local Variables:
437  * eval: (c-set-style "gnu")
438  * End:
439  */