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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vppinfra/error.h>
16 #include <vppinfra/hash.h>
17 #include <vnet/vnet.h>
18 #include <vnet/ip/ip.h>
19 #include <vnet/l2/l2_input.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/nsh-gre/nsh_gre.h>
23 nsh_gre_main_t nsh_gre_main;
25 static u8 * format_decap_next (u8 * s, va_list * args)
27 u32 next_index = va_arg (*args, u32);
31 case NSH_INPUT_NEXT_DROP:
32 return format (s, "drop");
33 case NSH_INPUT_NEXT_IP4_INPUT:
34 return format (s, "ip4");
35 case NSH_INPUT_NEXT_IP6_INPUT:
36 return format (s, "ip6");
38 return format (s, "index %d", next_index);
44 u8 * format_nsh_gre_tunnel (u8 * s, va_list * args)
46 nsh_gre_tunnel_t * t = va_arg (*args, nsh_gre_tunnel_t *);
47 nsh_gre_main_t * ngm = &nsh_gre_main;
49 s = format (s, "[%d] %U (src) %U (dst) fibs: (encap %d, decap %d)",
51 format_ip4_address, &t->src,
52 format_ip4_address, &t->dst,
56 s = format (s, " decap-next %U\n", format_decap_next, t->decap_next_index);
58 s = format (s, " ver %d ", (t->ver_o_c>>6));
59 if (t->ver_o_c & NSH_GRE_O_BIT)
60 s = format (s, "O-set ");
62 if (t->ver_o_c & NSH_GRE_C_BIT)
63 s = format (s, "C-set ");
65 s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
66 t->length, t->length * 4, t->md_type, t->next_protocol);
68 s = format (s, " service path %d service index %d\n",
69 (t->spi_si>>NSH_GRE_SPI_SHIFT) & NSH_GRE_SPI_MASK,
70 t->spi_si & NSH_GRE_SINDEX_MASK);
72 s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
73 t->c1, t->c2, t->c3, t->c4);
78 static u8 * format_nsh_gre_name (u8 * s, va_list * args)
80 nsh_gre_main_t * ngm = &nsh_gre_main;
81 u32 i = va_arg (*args, u32);
82 u32 show_dev_instance = ~0;
84 if (i < vec_len (ngm->dev_inst_by_real))
85 show_dev_instance = ngm->dev_inst_by_real[i];
87 if (show_dev_instance != ~0)
88 i = show_dev_instance;
90 return format (s, "nsh_gre_tunnel%d", i);
93 static int nsh_gre_name_renumber (vnet_hw_interface_t * hi,
96 nsh_gre_main_t * ngm = &nsh_gre_main;
98 vec_validate_init_empty (ngm->dev_inst_by_real, hi->dev_instance, ~0);
100 ngm->dev_inst_by_real [hi->dev_instance] = new_dev_instance;
105 static uword dummy_interface_tx (vlib_main_t * vm,
106 vlib_node_runtime_t * node,
107 vlib_frame_t * frame)
109 clib_warning ("you shouldn't be here, leaking buffers...");
110 return frame->n_vectors;
113 VNET_DEVICE_CLASS (nsh_gre_device_class,static) = {
115 .format_device_name = format_nsh_gre_name,
116 .format_tx_trace = format_nsh_gre_encap_trace,
117 .tx_function = dummy_interface_tx,
118 .name_renumber = nsh_gre_name_renumber,
121 static uword dummy_set_rewrite (vnet_main_t * vnm,
126 uword max_rewrite_bytes)
131 static u8 * format_nsh_gre_header_with_length (u8 * s, va_list * args)
133 u32 dev_instance = va_arg (*args, u32);
134 s = format (s, "unimplemented dev %u", dev_instance);
138 VNET_HW_INTERFACE_CLASS (nsh_gre_hw_class) = {
140 .format_header = format_nsh_gre_header_with_length,
141 .set_rewrite = dummy_set_rewrite,
144 #define foreach_copy_field \
149 _(decap_next_index) \
161 #define foreach_32bit_field \
168 static int nsh_gre_rewrite (nsh_gre_tunnel_t * t)
173 ip4_gre_and_nsh_header_t * h0;
176 len = sizeof (*h0) + vec_len(t->tlvs)*4;
178 vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
180 h0 = (ip4_gre_and_nsh_header_t *) rw;
182 /* Fixed portion of the (outer) ip4 header */
184 ip0->ip_version_and_header_length = 0x45;
186 ip0->protocol = IP_PROTOCOL_GRE;
187 /* we fix up the ip4 header length and checksum after-the-fact */
188 ip0->src_address.as_u32 = t->src.as_u32;
189 ip0->dst_address.as_u32 = t->dst.as_u32;
190 ip0->checksum = ip4_header_checksum (ip0);
192 /* GRE header, zero execpt for the NSH ethertype */
193 h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_nsh);
197 nsh0->ver_o_c = t->ver_o_c;
198 nsh0->md_type = t->md_type;
199 nsh0->next_protocol = t->next_protocol;
200 nsh0->spi_si = t->spi_si;
206 /* Endian swap 32-bit fields */
207 #define _(x) nsh0->x = clib_host_to_net_u32(nsh0->x);
211 /* fix nsh header length */
212 t->length = 6 + vec_len(t->tlvs);
213 nsh0->length = t->length;
216 if (vec_len(t->tlvs))
217 memcpy (nsh0->tlvs, t->tlvs, 4*vec_len(t->tlvs));
223 int vnet_nsh_gre_add_del_tunnel (vnet_nsh_gre_add_del_tunnel_args_t *a,
226 nsh_gre_main_t * ngm = &nsh_gre_main;
227 nsh_gre_tunnel_t *t = 0;
228 vnet_main_t * vnm = ngm->vnet_main;
229 vnet_hw_interface_t * hi;
231 u32 hw_if_index = ~0;
232 u32 sw_if_index = ~0;
235 u32 spi_si_net_byte_order;
237 spi_si_net_byte_order = clib_host_to_net_u32(a->spi_si);
239 key = (((u64)(a->src.as_u32))<<32) | spi_si_net_byte_order;
241 p = hash_get (ngm->nsh_gre_tunnel_by_src_address, key);
245 /* adding a tunnel: tunnel must not already exist */
247 return VNET_API_ERROR_INVALID_VALUE;
249 if (a->decap_next_index >= NSH_INPUT_N_NEXT)
250 return VNET_API_ERROR_INVALID_DECAP_NEXT;
252 pool_get_aligned (ngm->tunnels, t, CLIB_CACHE_LINE_BYTES);
253 memset (t, 0, sizeof (*t));
255 /* copy from arg structure */
256 #define _(x) t->x = a->x;
260 rv = nsh_gre_rewrite (t);
264 pool_put (ngm->tunnels, t);
268 hash_set (ngm->nsh_gre_tunnel_by_src_address, key, t - ngm->tunnels);
270 if (vec_len (ngm->free_nsh_gre_tunnel_hw_if_indices) > 0)
272 hw_if_index = ngm->free_nsh_gre_tunnel_hw_if_indices
273 [vec_len (ngm->free_nsh_gre_tunnel_hw_if_indices)-1];
274 _vec_len (ngm->free_nsh_gre_tunnel_hw_if_indices) -= 1;
276 hi = vnet_get_hw_interface (vnm, hw_if_index);
277 hi->dev_instance = t - ngm->tunnels;
278 hi->hw_instance = hi->dev_instance;
282 hw_if_index = vnet_register_interface
283 (vnm, nsh_gre_device_class.index, t - ngm->tunnels,
284 nsh_gre_hw_class.index, t - ngm->tunnels);
285 hi = vnet_get_hw_interface (vnm, hw_if_index);
286 hi->output_node_index = nsh_gre_encap_node.index;
289 t->hw_if_index = hw_if_index;
290 t->sw_if_index = sw_if_index = hi->sw_if_index;
292 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
293 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
297 /* deleting a tunnel: tunnel must exist */
299 return VNET_API_ERROR_NO_SUCH_ENTRY;
301 t = pool_elt_at_index (ngm->tunnels, p[0]);
303 vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */);
304 vec_add1 (ngm->free_nsh_gre_tunnel_hw_if_indices, t->hw_if_index);
306 hash_unset (ngm->nsh_gre_tunnel_by_src_address, key);
307 vec_free (t->rewrite);
308 pool_put (ngm->tunnels, t);
312 *sw_if_indexp = sw_if_index;
317 static u32 fib_index_from_fib_id (u32 fib_id)
319 ip4_main_t * im = &ip4_main;
322 p = hash_get (im->fib_index_by_table_id, fib_id);
329 static uword unformat_decap_next (unformat_input_t * input, va_list * args)
331 u32 * result = va_arg (*args, u32 *);
334 if (unformat (input, "drop"))
335 *result = NSH_INPUT_NEXT_DROP;
336 else if (unformat (input, "ip4"))
337 *result = NSH_INPUT_NEXT_IP4_INPUT;
338 else if (unformat (input, "ip6"))
339 *result = NSH_INPUT_NEXT_IP6_INPUT;
340 else if (unformat (input, "ethernet"))
341 *result = NSH_INPUT_NEXT_IP6_INPUT;
342 else if (unformat (input, "%d", &tmp))
349 static clib_error_t *
350 nsh_gre_add_del_tunnel_command_fn (vlib_main_t * vm,
351 unformat_input_t * input,
352 vlib_cli_command_t * cmd)
354 unformat_input_t _line_input, * line_input = &_line_input;
355 ip4_address_t src, dst;
359 u32 encap_fib_index = 0;
360 u32 decap_fib_index = 0;
364 u8 next_protocol = 1; /* ip4 */
374 u32 decap_next_index = 1; /* ip4_input */
378 vnet_nsh_gre_add_del_tunnel_args_t _a, * a = &_a;
380 /* Get a line of input. */
381 if (! unformat_user (input, unformat_line_input, line_input))
384 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
385 if (unformat (line_input, "del"))
387 else if (unformat (line_input, "src %U",
388 unformat_ip4_address, &src))
390 else if (unformat (line_input, "dst %U",
391 unformat_ip4_address, &dst))
393 else if (unformat (line_input, "encap-vrf-id %d", &tmp))
395 encap_fib_index = fib_index_from_fib_id (tmp);
396 if (encap_fib_index == ~0)
397 return clib_error_return (0, "nonexistent encap fib id %d", tmp);
399 else if (unformat (line_input, "decap-vrf-id %d", &tmp))
401 decap_fib_index = fib_index_from_fib_id (tmp);
402 if (decap_fib_index == ~0)
403 return clib_error_return (0, "nonexistent decap fib id %d", tmp);
405 else if (unformat (line_input, "decap-next %U", unformat_decap_next,
408 else if (unformat (line_input, "version %d", &tmp))
409 ver_o_c |= (tmp & 3) << 6;
410 else if (unformat (line_input, "o-bit %d", &tmp))
411 ver_o_c |= (tmp & 1) << 5;
412 else if (unformat (line_input, "c-bit %d", &tmp))
413 ver_o_c |= (tmp & 1) << 4;
414 else if (unformat (line_input, "md-type %d", &tmp))
416 else if (unformat(line_input, "next-ip4"))
418 else if (unformat(line_input, "next-ip6"))
420 else if (unformat(line_input, "next-ethernet"))
422 else if (unformat (line_input, "c1 %d", &c1))
424 else if (unformat (line_input, "c2 %d", &c2))
426 else if (unformat (line_input, "c3 %d", &c3))
428 else if (unformat (line_input, "c4 %d", &c4))
430 else if (unformat (line_input, "spi %d", &spi))
432 else if (unformat (line_input, "si %d", &si))
434 else if (unformat (line_input, "tlv %x"))
435 vec_add1 (tlvs, tmp);
437 return clib_error_return (0, "parse error: '%U'",
438 format_unformat_error, line_input);
441 unformat_free (line_input);
444 return clib_error_return (0, "tunnel src address not specified");
447 return clib_error_return (0, "tunnel dst address not specified");
450 return clib_error_return (0, "spi not specified");
453 return clib_error_return (0, "si not specified");
455 spi_si = (spi<<8) | si;
457 memset (a, 0, sizeof (*a));
461 #define _(x) a->x = x;
465 rv = vnet_nsh_gre_add_del_tunnel (a, 0 /* hw_if_indexp */);
471 case VNET_API_ERROR_INVALID_DECAP_NEXT:
472 return clib_error_return (0, "invalid decap-next...");
474 case VNET_API_ERROR_TUNNEL_EXIST:
475 return clib_error_return (0, "tunnel already exists...");
477 case VNET_API_ERROR_NO_SUCH_ENTRY:
478 return clib_error_return (0, "session does not exist...");
481 return clib_error_return
482 (0, "vnet_nsh_gre_add_del_tunnel returned %d", rv);
488 VLIB_CLI_COMMAND (create_nsh_gre_tunnel_command, static) = {
489 .path = "nsh gre tunnel",
491 "nsh gre tunnel src <ip4-addr> dst <ip4-addr>"
492 " c1 <nn> c2 <nn> c3 <nn> c4 <nn> spi <nn> si <nn>\n"
493 " [encap-fib-id <nn>] [decap-fib-id <nn>] [o-bit <1|0>] [c-bit <1|0>]\n"
494 " [md-type <nn>][next-ip4][next-ip6][next-ethernet]\n"
496 .function = nsh_gre_add_del_tunnel_command_fn,
499 static clib_error_t *
500 show_nsh_gre_tunnel_command_fn (vlib_main_t * vm,
501 unformat_input_t * input,
502 vlib_cli_command_t * cmd)
504 nsh_gre_main_t * ngm = &nsh_gre_main;
505 nsh_gre_tunnel_t * t;
507 if (pool_elts (ngm->tunnels) == 0)
508 vlib_cli_output (vm, "No nsh-gre tunnels configured...");
510 pool_foreach (t, ngm->tunnels,
512 vlib_cli_output (vm, "%U", format_nsh_gre_tunnel, t);
518 VLIB_CLI_COMMAND (show_nsh_gre_tunnel_command, static) = {
519 .path = "show nsh gre tunnel",
520 .function = show_nsh_gre_tunnel_command_fn,
523 clib_error_t *nsh_gre_init (vlib_main_t *vm)
525 nsh_gre_main_t *ngm = &nsh_gre_main;
527 ngm->vnet_main = vnet_get_main();
530 ngm->nsh_gre_tunnel_by_src_address = hash_create (0, sizeof (uword));
531 gre_register_input_protocol (vm, GRE_PROTOCOL_nsh,
532 nsh_gre_input_node.index);
536 VLIB_INIT_FUNCTION(nsh_gre_init);