Line data Source code
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 <gre/gre.h>
22 : #include <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 575 : 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 575 : 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 575 : key.class = class;
52 575 : key.type = type;
53 575 : key.pad = 0;
54 :
55 575 : p = hash_get_mem (nm->nsh_option_map_by_key, &key);
56 : /* Already registered */
57 575 : if (p != 0)
58 : {
59 0 : return (-1);
60 : }
61 :
62 575 : pool_get_aligned (nm->nsh_option_mappings, nsh_option,
63 : CLIB_CACHE_LINE_BYTES);
64 575 : clib_memset (nsh_option, 0, sizeof (*nsh_option));
65 575 : nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
66 :
67 575 : key_copy = clib_mem_alloc (sizeof (*key_copy));
68 575 : clib_memcpy (key_copy, &key, sizeof (*key_copy));
69 1150 : hash_set_mem (nm->nsh_option_map_by_key, key_copy,
70 : nsh_option - nm->nsh_option_mappings);
71 :
72 575 : if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t)))
73 : {
74 0 : return (-1);
75 : }
76 575 : nm->options_size[nsh_option->option_id] = option_size;
77 575 : nm->add_options[nsh_option->option_id] = add_options;
78 575 : nm->options[nsh_option->option_id] = options;
79 575 : nm->swap_options[nsh_option->option_id] = swap_options;
80 575 : nm->pop_options[nsh_option->option_id] = pop_options;
81 575 : nm->trace[nsh_option->option_id] = trace;
82 :
83 575 : return (0);
84 : }
85 :
86 : /* Uses network order's class and type to lookup */
87 : nsh_option_map_t *
88 0 : nsh_md2_lookup_option (u16 class, u8 type)
89 : {
90 0 : nsh_main_t *nm = &nsh_main;
91 : nsh_option_map_by_key_t key;
92 : uword *p;
93 :
94 0 : key.class = class;
95 0 : key.type = type;
96 0 : key.pad = 0;
97 :
98 0 : p = hash_get_mem (nm->nsh_option_map_by_key, &key);
99 : /* not registered */
100 0 : if (p == 0)
101 : {
102 0 : return NULL;
103 : }
104 :
105 0 : 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 0 : 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 0 : 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 0 : key.class = class;
124 0 : key.type = type;
125 0 : key.pad = 0;
126 :
127 0 : p = hash_get_mem (nm->nsh_option_map_by_key, &key);
128 : /* not registered */
129 0 : if (p == 0)
130 : {
131 0 : return (-1);
132 : }
133 :
134 0 : nsh_option = pool_elt_at_index (nm->nsh_option_mappings, p[0]);
135 0 : nm->options[nsh_option->option_id] = NULL;
136 0 : nm->add_options[nsh_option->option_id] = NULL;
137 0 : nm->pop_options[nsh_option->option_id] = NULL;
138 0 : nm->trace[nsh_option->option_id] = NULL;
139 :
140 0 : hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
141 0 : key_copy = (void *) (hp->key);
142 0 : hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
143 0 : clib_mem_free (key_copy);
144 :
145 0 : pool_put (nm->nsh_option_mappings, nsh_option);
146 :
147 0 : return (0);
148 : }
149 :
150 : /**
151 : * @brief Formatting function for tracing VXLAN GPE with length
152 : *
153 : * @param *s
154 : * @param *args
155 : *
156 : * @return *s
157 : *
158 : */
159 : static u8 *
160 0 : format_nsh_tunnel_with_length (u8 * s, va_list * args)
161 : {
162 0 : u32 dev_instance = va_arg (*args, u32);
163 0 : s = format (s, "unimplemented dev %u", dev_instance);
164 0 : return s;
165 : }
166 :
167 : /* *INDENT-OFF* */
168 2879 : VNET_HW_INTERFACE_CLASS (nsh_hw_class) = {
169 : .name = "NSH",
170 : .format_header = format_nsh_tunnel_with_length,
171 : .build_rewrite = default_build_rewrite,
172 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
173 : };
174 : /* *INDENT-ON* */
175 :
176 : void
177 0 : nsh_md2_set_next_ioam_export_override (uword next)
178 : {
179 0 : nsh_main_t *hm = &nsh_main;
180 0 : hm->decap_v4_next_override = next;
181 0 : return;
182 : }
183 :
184 : clib_error_t *
185 575 : nsh_init (vlib_main_t * vm)
186 : {
187 : vlib_node_t *node, *gre4_input, *gre6_input;
188 575 : nsh_main_t *nm = &nsh_main;
189 575 : clib_error_t *error = 0;
190 : uword next_node;
191 : vlib_node_registration_t *vxlan4_input, *vxlan6_input;
192 :
193 : /* Init the main structures from VPP */
194 575 : nm->vlib_main = vm;
195 575 : nm->vnet_main = vnet_get_main ();
196 :
197 : /* Various state maintenance mappings */
198 575 : nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
199 :
200 : nm->nsh_mapping_by_mapped_key
201 575 : = hash_create_mem (0, sizeof (u32), sizeof (uword));
202 :
203 575 : nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
204 :
205 : nm->nsh_proxy_session_by_key
206 575 : =
207 575 : hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword));
208 :
209 : nm->nsh_option_map_by_key
210 575 : = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword));
211 :
212 575 : error = nsh_api_init (vm, nm);
213 575 : if (error)
214 0 : return error;
215 :
216 575 : node = vlib_get_node_by_name (vm, (u8 *) "nsh-input");
217 575 : nm->nsh_input_node_index = node->index;
218 :
219 575 : node = vlib_get_node_by_name (vm, (u8 *) "nsh-proxy");
220 575 : nm->nsh_proxy_node_index = node->index;
221 :
222 575 : node = vlib_get_node_by_name (vm, (u8 *) "nsh-classifier");
223 575 : nm->nsh_classifier_node_index = node->index;
224 :
225 : /* Add dispositions to nodes that feed nsh-input */
226 : //alagalah - validate we don't really need to use the node value
227 : next_node =
228 575 : vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
229 575 : nm->nsh_input_node_index);
230 575 : vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
231 575 : nm->nsh_proxy_node_index);
232 575 : vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
233 575 : nsh_aware_vnf_proxy_node.index);
234 575 : vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
235 :
236 575 : vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
237 575 : nm->nsh_input_node_index);
238 575 : vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
239 575 : nm->nsh_proxy_node_index);
240 575 : vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
241 575 : nsh_aware_vnf_proxy_node.index);
242 :
243 575 : gre4_input = vlib_get_node_by_name (vm, (u8 *) "gre4-input");
244 575 : gre6_input = vlib_get_node_by_name (vm, (u8 *) "gre6-input");
245 575 : if (gre4_input == 0 || gre6_input == 0)
246 : {
247 0 : error = clib_error_return (0, "gre_plugin.so is not loaded");
248 0 : return error;
249 : }
250 575 : vlib_node_add_next (vm, gre4_input->index, nm->nsh_input_node_index);
251 575 : vlib_node_add_next (vm, gre4_input->index, nm->nsh_proxy_node_index);
252 575 : vlib_node_add_next (vm, gre4_input->index, nsh_aware_vnf_proxy_node.index);
253 575 : vlib_node_add_next (vm, gre6_input->index, nm->nsh_input_node_index);
254 575 : vlib_node_add_next (vm, gre6_input->index, nm->nsh_proxy_node_index);
255 575 : vlib_node_add_next (vm, gre6_input->index, nsh_aware_vnf_proxy_node.index);
256 :
257 : /* Add NSH-Proxy support */
258 : vxlan4_input =
259 575 : vlib_get_plugin_symbol ("vxlan_plugin.so", "vxlan4_input_node");
260 : vxlan6_input =
261 575 : vlib_get_plugin_symbol ("vxlan_plugin.so", "vxlan6_input_node");
262 575 : if (vxlan4_input == 0 || vxlan6_input == 0)
263 : {
264 0 : error = clib_error_return (0, "vxlan_plugin.so is not loaded");
265 0 : return error;
266 : }
267 575 : vlib_node_add_next (vm, vxlan4_input->index, nm->nsh_proxy_node_index);
268 575 : vlib_node_add_next (vm, vxlan6_input->index, nm->nsh_proxy_node_index);
269 :
270 : /* Add NSH-Classifier support */
271 575 : vlib_node_add_next (vm, ip4_classify_node.index,
272 575 : nm->nsh_classifier_node_index);
273 575 : vlib_node_add_next (vm, ip6_classify_node.index,
274 575 : nm->nsh_classifier_node_index);
275 575 : vlib_node_add_next (vm, l2_input_classify_node.index,
276 575 : nm->nsh_classifier_node_index);
277 :
278 : /* Add Ethernet+NSH support */
279 575 : ethernet_register_input_type (vm, ETHERNET_TYPE_NSH,
280 : nm->nsh_input_node_index);
281 :
282 575 : return error;
283 : }
284 :
285 1151 : VLIB_INIT_FUNCTION (nsh_init);
286 :
287 : /* *INDENT-OFF* */
288 : VLIB_PLUGIN_REGISTER () = {
289 : .version = VPP_BUILD_VER,
290 : .description = "Network Service Header (NSH)",
291 : };
292 : /* *INDENT-ON* */
293 :
294 : /*
295 : * fd.io coding-style-patch-verification: ON
296 : *
297 : * Local Variables:
298 : * eval: (c-set-style "gnu")
299 : * End:
300 : */
|