Deprecate MPLSoGRE tunnels (VPP-502)
[vpp.git] / vnet / vnet / mpls / mpls_features.c
1 /*
2  * mpls_features.c: MPLS input and output features
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/mpls/mpls.h>
19
20 always_inline uword
21 mpls_terminate (vlib_main_t * vm,
22                 vlib_node_runtime_t * node,
23                 vlib_frame_t * frame,
24                 int error_code)
25 {
26   u32 * buffers = vlib_frame_vector_args (frame);
27   uword n_packets = frame->n_vectors;
28
29   vlib_error_drop_buffers (vm, node,
30                            buffers,
31                            /* stride */ 1,
32                            n_packets,
33                            /* next */ 0,
34                            mpls_input_node.index,
35                            error_code);
36
37   return n_packets;
38 }
39
40 static uword
41 mpls_punt (vlib_main_t * vm,
42            vlib_node_runtime_t * node,
43            vlib_frame_t * frame)
44 {
45     return (mpls_terminate(vm, node, frame, MPLS_ERROR_PUNT));
46 }
47
48 VLIB_REGISTER_NODE (mpls_punt_node) = {
49   .function = mpls_punt,
50   .name = "mpls-punt",
51   .vector_size = sizeof (u32),
52
53   .n_next_nodes = 1,
54   .next_nodes = {
55     [0] = "error-punt",
56   },
57 };
58
59 VLIB_NODE_FUNCTION_MULTIARCH (mpls_punt_node, mpls_punt)
60
61 static uword
62 mpls_drop (vlib_main_t * vm,
63            vlib_node_runtime_t * node,
64            vlib_frame_t * frame)
65 {
66     return (mpls_terminate(vm, node, frame, MPLS_ERROR_DROP));
67 }
68
69 VLIB_REGISTER_NODE (mpls_drop_node) = {
70   .function = mpls_drop,
71   .name = "mpls-drop",
72   .vector_size = sizeof (u32),
73
74   .n_next_nodes = 1,
75   .next_nodes = {
76     [0] = "error-drop",
77   },
78 };
79
80 VLIB_NODE_FUNCTION_MULTIARCH (mpls_drop_node, mpls_drop)
81
82 static uword
83 mpls_not_enabled (vlib_main_t * vm,
84                   vlib_node_runtime_t * node,
85                   vlib_frame_t * frame)
86 {
87     return (mpls_terminate(vm, node, frame, MPLS_ERROR_NOT_ENABLED));
88 }
89
90 VLIB_REGISTER_NODE (mpls_not_enabled_node) = {
91   .function = mpls_not_enabled,
92   .name = "mpls-not-enabled",
93   .vector_size = sizeof (u32),
94
95   .n_next_nodes = 1,
96   .next_nodes = {
97     [0] = "error-drop",
98   },
99 };
100
101 VLIB_NODE_FUNCTION_MULTIARCH (mpls_not_enabled_node, mpls_not_enabled)
102
103 VNET_MPLS_FEATURE_INIT (mpls_lookup, static) = {
104   .node_name = "mpls-lookup",
105   .runs_before = ORDER_CONSTRAINTS {"mpls-not-enabled", 0},
106   .feature_index = &mpls_main.mpls_rx_feature_lookup,
107 };
108
109 VNET_MPLS_FEATURE_INIT (mpls_not_enabled, static) = {
110   .node_name = "mpls-not-enabled",
111   .runs_before = ORDER_CONSTRAINTS {0}, /* not before any other features */
112   .feature_index = &mpls_main.mpls_rx_feature_not_enabled,
113 };
114
115 /* Built-in ip4 tx feature path definition */
116 VNET_MPLS_TX_FEATURE_INIT (interface_output, static) = {
117   .node_name = "interface-output",
118   .runs_before = 0, /* not before any other features */
119   .feature_index = &mpls_main.mpls_tx_feature_interface_output,
120 };
121
122
123 static char * rx_feature_start_nodes[] =
124 {
125     "mpls-input",
126 };
127 static char * tx_feature_start_nodes[] =
128 {
129     "mpls-output",
130     "mpls-midchain",
131 };
132
133 clib_error_t *
134 mpls_feature_init (vlib_main_t * vm)
135 {
136   ip_config_main_t * cm = &mpls_main.feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
137   vnet_config_main_t * vcm = &cm->config_main;
138   clib_error_t *error;
139
140   error = vnet_feature_arc_init
141       (vm, vcm, rx_feature_start_nodes,
142        ARRAY_LEN(rx_feature_start_nodes),
143        mpls_main.next_feature[VNET_IP_RX_UNICAST_FEAT],
144        &mpls_main.feature_nodes[VNET_IP_RX_UNICAST_FEAT]);
145
146   if (error)
147       return error;
148
149   cm  = &mpls_main.feature_config_mains[VNET_IP_TX_FEAT];
150   vcm = &cm->config_main;
151
152   error = vnet_feature_arc_init
153       (vm, vcm,
154        tx_feature_start_nodes,
155        ARRAY_LEN(tx_feature_start_nodes),
156        mpls_main.next_feature[VNET_IP_TX_FEAT],
157        &mpls_main.feature_nodes[VNET_IP_TX_FEAT]);
158
159   return error;
160 }
161
162 static clib_error_t *
163 mpls_sw_interface_add_del (vnet_main_t * vnm,
164                            u32 sw_if_index,
165                            u32 is_add)
166 {
167   vlib_main_t * vm = vnm->vlib_main;
168   mpls_main_t * mm = &mpls_main;
169   u32 feature_index;
170   u32 ci, cast;
171
172   for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
173   {
174       ip_config_main_t * cm = &mm->feature_config_mains[cast];
175       vnet_config_main_t * vcm = &cm->config_main;
176
177       if (VNET_IP_RX_MULTICAST_FEAT == cast)
178           continue;
179
180       vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
181       vec_validate_init_empty (mm->fib_index_by_sw_if_index, sw_if_index, 0);
182       vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
183       ci = cm->config_index_by_sw_if_index[sw_if_index];
184
185        if (cast == VNET_IP_RX_UNICAST_FEAT)
186            feature_index = mm->mpls_rx_feature_not_enabled;
187        else
188            feature_index = mm->mpls_tx_feature_interface_output;
189
190
191       if (is_add)
192           ci = vnet_config_add_feature (vm, vcm, ci,
193                                         feature_index,
194                                         /* config data */ 0,
195                                         /* # bytes of config data */ 0);
196       else
197       {
198           ci = vnet_config_del_feature (vm, vcm, ci,
199                                         feature_index,
200                                         /* config data */ 0,
201                                         /* # bytes of config data */ 0);
202           mm->mpls_enabled_by_sw_if_index[sw_if_index] = 0;;
203       }
204       cm->config_index_by_sw_if_index[sw_if_index] = ci;
205   }
206
207   return /* no error */ 0;
208 }
209
210 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (mpls_sw_interface_add_del);
211
212 #define foreach_af_cast                         \
213 _(VNET_IP_RX_UNICAST_FEAT, "mpls input")        \
214 _(VNET_IP_TX_FEAT, "mpls output")               \
215
216 static clib_error_t *
217 show_mpls_features_command_fn (vlib_main_t * vm,
218                                unformat_input_t * input,
219                                vlib_cli_command_t * cmd)
220 {
221   mpls_main_t * mm = &mpls_main;
222   int i;
223   char ** features;
224
225   vlib_cli_output (vm, "Available MPLS feature nodes");
226
227 #define _(c,s)                                          \
228   do {                                                  \
229     features = mm->feature_nodes[c];                    \
230     vlib_cli_output (vm, "%s:", s);                     \
231     for (i = 0; i < vec_len(features); i++)             \
232       vlib_cli_output (vm, "  %s\n", features[i]);      \
233   } while(0);
234   foreach_af_cast;
235 #undef _
236
237   return 0;
238 }
239
240 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
241   .path = "show mpls features",
242   .short_help = "show mpls features",
243   .function = show_mpls_features_command_fn,
244 };
245
246 static clib_error_t *
247 show_mpls_interface_features_command_fn (vlib_main_t * vm,
248                                          unformat_input_t * input,
249                                          vlib_cli_command_t * cmd)
250 {
251   vnet_main_t * vnm = vnet_get_main();
252   u32 sw_if_index;
253
254   if (! unformat (input, "%U", unformat_vnet_sw_interface,
255                   vnm, &sw_if_index))
256     return clib_error_return (0, "Interface not specified...");
257
258   vlib_cli_output (vm, "MPLS feature paths configured on %U...",
259                    format_vnet_sw_if_index_name, vnm, sw_if_index);
260
261   ip_interface_features_show (vm, "MPLS",
262                               mpls_main.feature_config_mains,
263                               sw_if_index);
264
265   return 0;
266 }
267
268 VLIB_CLI_COMMAND (show_mpls_interface_features_command, static) = {
269   .path = "show mpls interface features",
270   .short_help = "show mpls interface features <intfc>",
271   .function = show_mpls_interface_features_command_fn,
272 };
273