nsh: migrate old MUTIARCH macros to VLIB_NODE_FN
[vpp.git] / src / plugins / nsh / nsh.c
1 /*
2  * nsh.c - nsh mapping
3  *
4  * Copyright (c) 2013 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/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <nsh/nsh.h>
21 #include <vnet/gre/gre.h>
22 #include <vnet/vxlan/vxlan.h>
23 #include <vnet/vxlan-gpe/vxlan_gpe.h>
24 #include <vnet/l2/l2_classify.h>
25 #include <vnet/adj/adj.h>
26 #include <vpp/app/version.h>
27
28 nsh_main_t nsh_main;
29
30 /* Uses network order's class and type to register */
31 int
32 nsh_md2_register_option (u16 class,
33                          u8 type,
34                          u8 option_size,
35                          int add_options (u8 * opt,
36                                           u8 * opt_size),
37                          int options (vlib_buffer_t * b,
38                                       nsh_tlv_header_t * opt),
39                          int swap_options (vlib_buffer_t * b,
40                                            nsh_tlv_header_t * old_opt,
41                                            nsh_tlv_header_t * new_opt),
42                          int pop_options (vlib_buffer_t * b,
43                                           nsh_tlv_header_t * opt),
44                          u8 * trace (u8 * s, nsh_tlv_header_t * opt))
45 {
46   nsh_main_t *nm = &nsh_main;
47   nsh_option_map_by_key_t key, *key_copy;
48   uword *p;
49   nsh_option_map_t *nsh_option;
50
51   key.class = class;
52   key.type = type;
53   key.pad = 0;
54
55   p = hash_get_mem (nm->nsh_option_map_by_key, &key);
56   /* Already registered */
57   if (p != 0)
58     {
59       return (-1);
60     }
61
62   pool_get_aligned (nm->nsh_option_mappings, nsh_option,
63                     CLIB_CACHE_LINE_BYTES);
64   clib_memset (nsh_option, 0, sizeof (*nsh_option));
65   nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
66
67   key_copy = clib_mem_alloc (sizeof (*key_copy));
68   clib_memcpy (key_copy, &key, sizeof (*key_copy));
69   hash_set_mem (nm->nsh_option_map_by_key, key_copy,
70                 nsh_option - nm->nsh_option_mappings);
71
72   if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t)))
73     {
74       return (-1);
75     }
76   nm->options_size[nsh_option->option_id] = option_size;
77   nm->add_options[nsh_option->option_id] = add_options;
78   nm->options[nsh_option->option_id] = options;
79   nm->swap_options[nsh_option->option_id] = swap_options;
80   nm->pop_options[nsh_option->option_id] = pop_options;
81   nm->trace[nsh_option->option_id] = trace;
82
83   return (0);
84 }
85
86 /* Uses network order's class and type to lookup */
87 nsh_option_map_t *
88 nsh_md2_lookup_option (u16 class, u8 type)
89 {
90   nsh_main_t *nm = &nsh_main;
91   nsh_option_map_by_key_t key;
92   uword *p;
93
94   key.class = class;
95   key.type = type;
96   key.pad = 0;
97
98   p = hash_get_mem (nm->nsh_option_map_by_key, &key);
99   /* not registered */
100   if (p == 0)
101     {
102       return NULL;
103     }
104
105   return pool_elt_at_index (nm->nsh_option_mappings, p[0]);
106
107 }
108
109 /* Uses network order's class and type to unregister */
110 int
111 nsh_md2_unregister_option (u16 class,
112                            u8 type,
113                            int options (vlib_buffer_t * b,
114                                         nsh_tlv_header_t * opt),
115                            u8 * trace (u8 * s, nsh_tlv_header_t * opt))
116 {
117   nsh_main_t *nm = &nsh_main;
118   nsh_option_map_by_key_t key, *key_copy;
119   uword *p;
120   hash_pair_t *hp;
121   nsh_option_map_t *nsh_option;
122
123   key.class = class;
124   key.type = type;
125   key.pad = 0;
126
127   p = hash_get_mem (nm->nsh_option_map_by_key, &key);
128   /* not registered */
129   if (p == 0)
130     {
131       return (-1);
132     }
133
134   nsh_option = pool_elt_at_index (nm->nsh_option_mappings, p[0]);
135   nm->options[nsh_option->option_id] = NULL;
136   nm->add_options[nsh_option->option_id] = NULL;
137   nm->pop_options[nsh_option->option_id] = NULL;
138   nm->trace[nsh_option->option_id] = NULL;
139
140   hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
141   key_copy = (void *) (hp->key);
142   hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
143   clib_mem_free (key_copy);
144
145   pool_put (nm->nsh_option_mappings, nsh_option);
146
147   return (0);
148 }
149
150 /**
151  * @brief Naming for NSH tunnel
152  *
153  * @param *s formatting string
154  * @param *args
155  *
156  * @return *s formatted string
157  *
158  */
159 static u8 *
160 format_nsh_name (u8 * s, va_list * args)
161 {
162   u32 dev_instance = va_arg (*args, u32);
163   return format (s, "nsh_tunnel%d", dev_instance);
164 }
165
166 /**
167  * @brief CLI function for NSH admin up/down
168  *
169  * @param *vnm
170  * @param nsh_hw_if
171  * @param flag
172  *
173  * @return *rc
174  *
175  */
176 static clib_error_t *
177 nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
178 {
179   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
180     vnet_hw_interface_set_flags (vnm, nsh_hw_if,
181                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
182   else
183     vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
184
185   return 0;
186 }
187
188 static uword
189 dummy_interface_tx (vlib_main_t * vm,
190                     vlib_node_runtime_t * node, vlib_frame_t * frame)
191 {
192   clib_warning ("you shouldn't be here, leaking buffers...");
193   return frame->n_vectors;
194 }
195
196 /* *INDENT-OFF* */
197 VNET_DEVICE_CLASS (nsh_device_class, static) = {
198   .name = "NSH",
199   .format_device_name = format_nsh_name,
200   .tx_function = dummy_interface_tx,
201   .admin_up_down_function = nsh_interface_admin_up_down,
202 };
203 /* *INDENT-ON* */
204
205 /**
206  * @brief Formatting function for tracing VXLAN GPE with length
207  *
208  * @param *s
209  * @param *args
210  *
211  * @return *s
212  *
213  */
214 static u8 *
215 format_nsh_tunnel_with_length (u8 * s, va_list * args)
216 {
217   u32 dev_instance = va_arg (*args, u32);
218   s = format (s, "unimplemented dev %u", dev_instance);
219   return s;
220 }
221
222 /* *INDENT-OFF* */
223 VNET_HW_INTERFACE_CLASS (nsh_hw_class) = {
224   .name = "NSH",
225   .format_header = format_nsh_tunnel_with_length,
226   .build_rewrite = default_build_rewrite,
227   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
228 };
229 /* *INDENT-ON* */
230
231 void
232 nsh_md2_set_next_ioam_export_override (uword next)
233 {
234   nsh_main_t *hm = &nsh_main;
235   hm->decap_v4_next_override = next;
236   return;
237 }
238
239 clib_error_t *
240 nsh_init (vlib_main_t * vm)
241 {
242   vlib_node_t *node;
243   nsh_main_t *nm = &nsh_main;
244   clib_error_t *error = 0;
245   uword next_node;
246
247   /* Init the main structures from VPP */
248   nm->vlib_main = vm;
249   nm->vnet_main = vnet_get_main ();
250
251   /* Various state maintenance mappings */
252   nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
253
254   nm->nsh_mapping_by_mapped_key
255     = hash_create_mem (0, sizeof (u32), sizeof (uword));
256
257   nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
258
259   nm->nsh_proxy_session_by_key
260     =
261     hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword));
262
263   nm->nsh_option_map_by_key
264     = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword));
265
266   error = nsh_api_init (vm, nm);
267   if (error)
268     return error;
269
270   node = vlib_get_node_by_name (vm, (u8 *) "nsh-input");
271   nm->nsh_input_node_index = node->index;
272
273   node = vlib_get_node_by_name (vm, (u8 *) "nsh-proxy");
274   nm->nsh_proxy_node_index = node->index;
275
276   node = vlib_get_node_by_name (vm, (u8 *) "nsh-classifier");
277   nm->nsh_classifier_node_index = node->index;
278
279   /* Add dispositions to nodes that feed nsh-input */
280   //alagalah - validate we don't really need to use the node value
281   next_node =
282     vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
283                         nm->nsh_input_node_index);
284   vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
285                       nm->nsh_proxy_node_index);
286   vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
287                       nsh_aware_vnf_proxy_node.index);
288   vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
289
290   vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
291                       nm->nsh_input_node_index);
292   vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
293                       nm->nsh_proxy_node_index);
294   vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
295                       nsh_aware_vnf_proxy_node.index);
296
297   vlib_node_add_next (vm, gre4_input_node.index, nm->nsh_input_node_index);
298   vlib_node_add_next (vm, gre4_input_node.index, nm->nsh_proxy_node_index);
299   vlib_node_add_next (vm, gre4_input_node.index,
300                       nsh_aware_vnf_proxy_node.index);
301
302   vlib_node_add_next (vm, gre6_input_node.index, nm->nsh_input_node_index);
303   vlib_node_add_next (vm, gre6_input_node.index, nm->nsh_proxy_node_index);
304   vlib_node_add_next (vm, gre6_input_node.index,
305                       nsh_aware_vnf_proxy_node.index);
306
307   /* Add NSH-Proxy support */
308   vlib_node_add_next (vm, vxlan4_input_node.index, nm->nsh_proxy_node_index);
309   vlib_node_add_next (vm, vxlan6_input_node.index, nm->nsh_proxy_node_index);
310
311   /* Add NSH-Classifier support */
312   vlib_node_add_next (vm, ip4_classify_node.index,
313                       nm->nsh_classifier_node_index);
314   vlib_node_add_next (vm, ip6_classify_node.index,
315                       nm->nsh_classifier_node_index);
316   vlib_node_add_next (vm, l2_input_classify_node.index,
317                       nm->nsh_classifier_node_index);
318
319   /* Add Ethernet+NSH support */
320   ethernet_register_input_type (vm, ETHERNET_TYPE_NSH,
321                                 nm->nsh_input_node_index);
322
323   return error;
324 }
325
326 VLIB_INIT_FUNCTION (nsh_init);
327
328 /* *INDENT-OFF* */
329 VLIB_PLUGIN_REGISTER () = {
330     .version = VPP_BUILD_VER,
331     .description = "Network Service Header",
332 };
333 /* *INDENT-ON* */
334
335 /*
336  * fd.io coding-style-patch-verification: ON
337  *
338  * Local Variables:
339  * eval: (c-set-style "gnu")
340  * End:
341  */