L2 over LISP and GRE (VPP-457)
[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   if ((error = ip_feature_init_cast (vm, cm, vcm,
141                                      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       return error;
146
147   cm  = &mpls_main.feature_config_mains[VNET_IP_TX_FEAT];
148   vcm = &cm->config_main;
149
150   if ((error = ip_feature_init_cast (vm, cm, vcm,
151                                      tx_feature_start_nodes,
152                                      ARRAY_LEN(tx_feature_start_nodes),
153                                      mpls_main.next_feature[VNET_IP_TX_FEAT],
154                                      &mpls_main.feature_nodes[VNET_IP_TX_FEAT])))
155       return error;
156
157   return error;
158 }
159
160 static clib_error_t *
161 mpls_sw_interface_add_del (vnet_main_t * vnm,
162                            u32 sw_if_index,
163                            u32 is_add)
164 {
165   vlib_main_t * vm = vnm->vlib_main;
166   mpls_main_t * mm = &mpls_main;
167   u32 feature_index;
168   u32 ci, cast;
169
170   for (cast = 0; cast < VNET_N_IP_FEAT; cast++)
171   {
172       ip_config_main_t * cm = &mm->feature_config_mains[cast];
173       vnet_config_main_t * vcm = &cm->config_main;
174
175       if (VNET_IP_RX_MULTICAST_FEAT == cast)
176           continue;
177
178       vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
179       vec_validate_init_empty (mm->fib_index_by_sw_if_index, sw_if_index, 0);
180       vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
181       ci = cm->config_index_by_sw_if_index[sw_if_index];
182
183        if (cast == VNET_IP_RX_UNICAST_FEAT)
184            feature_index = mm->mpls_rx_feature_not_enabled;
185        else
186            feature_index = mm->mpls_tx_feature_interface_output;
187
188
189       if (is_add)
190           ci = vnet_config_add_feature (vm, vcm, ci,
191                                         feature_index,
192                                         /* config data */ 0,
193                                         /* # bytes of config data */ 0);
194       else
195       {
196           ci = vnet_config_del_feature (vm, vcm, ci,
197                                         feature_index,
198                                         /* config data */ 0,
199                                         /* # bytes of config data */ 0);
200           mm->mpls_enabled_by_sw_if_index[sw_if_index] = 0;;
201       }
202       cm->config_index_by_sw_if_index[sw_if_index] = ci;
203   }
204
205   return /* no error */ 0;
206 }
207
208 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (mpls_sw_interface_add_del);
209
210 #define foreach_af_cast                         \
211 _(VNET_IP_RX_UNICAST_FEAT, "mpls input")        \
212 _(VNET_IP_TX_FEAT, "mpls output")               \
213
214 static clib_error_t *
215 show_mpls_features_command_fn (vlib_main_t * vm,
216                                unformat_input_t * input,
217                                vlib_cli_command_t * cmd)
218 {
219   mpls_main_t * mm = &mpls_main;
220   int i;
221   char ** features;
222
223   vlib_cli_output (vm, "Available MPLS feature nodes");
224
225 #define _(c,s)                                          \
226   do {                                                  \
227     features = mm->feature_nodes[c];                    \
228     vlib_cli_output (vm, "%s:", s);                     \
229     for (i = 0; i < vec_len(features); i++)             \
230       vlib_cli_output (vm, "  %s\n", features[i]);      \
231   } while(0);
232   foreach_af_cast;
233 #undef _
234
235   return 0;
236 }
237
238 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
239   .path = "show mpls features",
240   .short_help = "show mpls features",
241   .function = show_mpls_features_command_fn,
242 };
243
244 static clib_error_t *
245 show_mpls_interface_features_command_fn (vlib_main_t * vm,
246                                          unformat_input_t * input,
247                                          vlib_cli_command_t * cmd)
248 {
249   vnet_main_t * vnm = vnet_get_main();
250   u32 sw_if_index;
251
252   if (! unformat (input, "%U", unformat_vnet_sw_interface,
253                   vnm, &sw_if_index))
254     return clib_error_return (0, "Interface not specified...");
255
256   vlib_cli_output (vm, "MPLS feature paths configured on %U...",
257                    format_vnet_sw_if_index_name, vnm, sw_if_index);
258
259   ip_interface_features_show (vm, "MPLS", 
260                               mpls_main.feature_config_mains,
261                               sw_if_index);
262
263   return 0;
264 }
265
266 VLIB_CLI_COMMAND (show_mpls_interface_features_command, static) = {
267   .path = "show mpls interface features",
268   .short_help = "show mpls interface features <intfc>",
269   .function = show_mpls_interface_features_command_fn,
270 };
271