blob: d624587d8e9d0612a30d2f2389154974854651bd [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * gre_interface.c: gre interfaces
3 *
4 * Copyright (c) 2012 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/pg/pg.h>
20#include <vnet/gre/gre.h>
Chris Luke27fe48f2016-04-28 13:44:38 -040021#include <vnet/ip/format.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010022#include <vnet/fib/ip4_fib.h>
23#include <vnet/adj/adj_midchain.h>
Neale Rannsb80c5362016-10-08 13:03:40 +010024#include <vnet/adj/adj_nbr.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010025#include <vnet/mpls/mpls.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070026
Neale Ranns177bbdc2016-11-15 09:46:51 +000027static const char *gre_tunnel_type_names[] = GRE_TUNNEL_TYPE_NAMES;
28
Neale Ranns0bfe5d82016-08-25 15:29:12 +010029static inline u64
30gre_mk_key (const ip4_address_t *src,
31 const ip4_address_t *dst,
32 u32 out_fib_index)
33{
34 // FIXME. the fib index should be part of the key
35 return ((u64)src->as_u32 << 32 | (u64)dst->as_u32);
36}
37
38static u8 *
Neale Ranns177bbdc2016-11-15 09:46:51 +000039format_gre_tunnel_type (u8 * s, va_list * args)
40{
41 gre_tunnel_type_t type = va_arg (*args, gre_tunnel_type_t);
42
43 return (format(s, "%s", gre_tunnel_type_names[type]));
44}
45
46static u8 *
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047format_gre_tunnel (u8 * s, va_list * args)
Chris Luke27fe48f2016-04-28 13:44:38 -040048{
49 gre_tunnel_t * t = va_arg (*args, gre_tunnel_t *);
50 gre_main_t * gm = &gre_main;
51
52 s = format (s,
Neale Ranns177bbdc2016-11-15 09:46:51 +000053 "[%d] %U (src) %U (dst) payload %U outer_fib_index %d",
Chris Luke27fe48f2016-04-28 13:44:38 -040054 t - gm->tunnels,
55 format_ip4_address, &t->tunnel_src,
56 format_ip4_address, &t->tunnel_dst,
Neale Ranns177bbdc2016-11-15 09:46:51 +000057 format_gre_tunnel_type, t->type,
Chris Luke27fe48f2016-04-28 13:44:38 -040058 t->outer_fib_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010059
Chris Luke27fe48f2016-04-28 13:44:38 -040060 return s;
61}
62
Neale Ranns0bfe5d82016-08-25 15:29:12 +010063static gre_tunnel_t *
64gre_tunnel_db_find (const ip4_address_t *src,
65 const ip4_address_t *dst,
66 u32 out_fib_index)
67{
68 gre_main_t * gm = &gre_main;
69 uword * p;
70 u64 key;
71
72 key = gre_mk_key(src, dst, out_fib_index);
73
74 p = hash_get (gm->tunnel_by_key, key);
75
76 if (NULL == p)
77 return (NULL);
78
79 return (pool_elt_at_index (gm->tunnels, p[0]));
80}
81
82static void
83gre_tunnel_db_add (const gre_tunnel_t *t)
84{
85 gre_main_t * gm = &gre_main;
86 u64 key;
87
88 key = gre_mk_key(&t->tunnel_src, &t->tunnel_dst, t->outer_fib_index);
89 hash_set (gm->tunnel_by_key, key, t - gm->tunnels);
90}
91
92static void
93gre_tunnel_db_remove (const gre_tunnel_t *t)
94{
95 gre_main_t * gm = &gre_main;
96 u64 key;
97
98 key = gre_mk_key(&t->tunnel_src, &t->tunnel_dst, t->outer_fib_index);
99 hash_unset (gm->tunnel_by_key, key);
100}
101
102static gre_tunnel_t *
103gre_tunnel_from_fib_node (fib_node_t *node)
104{
105#if (CLIB_DEBUG > 0)
106 ASSERT(FIB_NODE_TYPE_GRE_TUNNEL == node->fn_type);
107#endif
108 return ((gre_tunnel_t*) (((char*)node) -
109 STRUCT_OFFSET_OF(gre_tunnel_t, node)));
110}
111
Neale Ranns5e575b12016-10-03 09:40:25 +0100112/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113 * gre_tunnel_stack
114 *
115 * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
116 */
Neale Ranns5e575b12016-10-03 09:40:25 +0100117void
Neale Rannsb80c5362016-10-08 13:03:40 +0100118gre_tunnel_stack (adj_index_t ai)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100119{
Neale Rannsb80c5362016-10-08 13:03:40 +0100120 gre_main_t * gm = &gre_main;
121 ip_adjacency_t *adj;
122 gre_tunnel_t *gt;
123 u32 sw_if_index;
124
125 adj = adj_get(ai);
126 sw_if_index = adj->rewrite_header.sw_if_index;
127
128 if ((vec_len(gm->tunnel_index_by_sw_if_index) < sw_if_index) ||
129 (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
130 return;
131
132 gt = pool_elt_at_index(gm->tunnels,
133 gm->tunnel_index_by_sw_if_index[sw_if_index]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100134
135 /*
136 * find the adjacency that is contributed by the FIB entry
137 * that this tunnel resovles via, and use it as the next adj
138 * in the midchain
139 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100140 if (vnet_hw_interface_get_flags(vnet_get_main(),
141 gt->hw_if_index) &
142 VNET_HW_INTERFACE_FLAG_LINK_UP)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100143 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100144 adj_nbr_midchain_stack(
145 ai,
146 fib_entry_contribute_ip_forwarding(gt->fib_entry_index));
147 }
148 else
149 {
150 adj_nbr_midchain_unstack(ai);
151 }
152}
153
154/**
155 * @brief Call back when restacking all adjacencies on a GRE interface
156 */
157static adj_walk_rc_t
158gre_adj_walk_cb (adj_index_t ai,
159 void *ctx)
160{
161 gre_tunnel_stack(ai);
162
163 return (ADJ_WALK_RC_CONTINUE);
164}
165
166static void
167gre_tunnel_restack (gre_tunnel_t *gt)
168{
169 fib_protocol_t proto;
170
171 /*
172 * walk all the adjacencies on th GRE interface and restack them
173 */
174 FOR_EACH_FIB_IP_PROTOCOL(proto)
175 {
176 adj_nbr_walk(gt->sw_if_index,
177 proto,
178 gre_adj_walk_cb,
179 NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180 }
181}
182
183/**
184 * Function definition to backwalk a FIB node
185 */
186static fib_node_back_walk_rc_t
187gre_tunnel_back_walk (fib_node_t *node,
Neale Rannsb80c5362016-10-08 13:03:40 +0100188 fib_node_back_walk_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100189{
Neale Rannsb80c5362016-10-08 13:03:40 +0100190 gre_tunnel_restack(gre_tunnel_from_fib_node(node));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100191
192 return (FIB_NODE_BACK_WALK_CONTINUE);
193}
194
195/**
196 * Function definition to get a FIB node from its index
197 */
198static fib_node_t*
199gre_tunnel_fib_node_get (fib_node_index_t index)
200{
201 gre_tunnel_t * gt;
202 gre_main_t * gm;
203
204 gm = &gre_main;
205 gt = pool_elt_at_index(gm->tunnels, index);
206
207 return (&gt->node);
208}
209
210/**
211 * Function definition to inform the FIB node that its last lock has gone.
212 */
213static void
214gre_tunnel_last_lock_gone (fib_node_t *node)
215{
216 /*
217 * The MPLS GRE tunnel is a root of the graph. As such
218 * it never has children and thus is never locked.
219 */
220 ASSERT(0);
221}
222
223/*
224 * Virtual function table registered by MPLS GRE tunnels
225 * for participation in the FIB object graph.
226 */
227const static fib_node_vft_t gre_vft = {
228 .fnv_get = gre_tunnel_fib_node_get,
229 .fnv_last_lock = gre_tunnel_last_lock_gone,
230 .fnv_back_walk = gre_tunnel_back_walk,
231};
232
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100233static int
234vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t *a,
235 u32 * sw_if_indexp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236{
237 gre_main_t * gm = &gre_main;
Chris Luke27fe48f2016-04-28 13:44:38 -0400238 vnet_main_t * vnm = gm->vnet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 ip4_main_t * im = &ip4_main;
240 gre_tunnel_t * t;
241 vnet_hw_interface_t * hi;
Chris Luke27fe48f2016-04-28 13:44:38 -0400242 u32 hw_if_index, sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 u32 outer_fib_index;
David Hothama8cd3092016-09-19 09:55:07 -0700244 u8 address[6];
245 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100247 outer_fib_index = ip4_fib_index_from_table_id(a->outer_fib_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100249 if (~0 == outer_fib_index)
250 return VNET_API_ERROR_NO_SUCH_FIB;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100252 t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100254 if (NULL != t)
255 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257 pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
258 memset (t, 0, sizeof (*t));
259 fib_node_init(&t->node, FIB_NODE_TYPE_GRE_TUNNEL);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260
Neale Ranns177bbdc2016-11-15 09:46:51 +0000261 if (a->teb)
262 t->type = GRE_TUNNEL_TYPE_TEB;
263 else
264 t->type = GRE_TUNNEL_TYPE_L3;
265
266 if (vec_len (gm->free_gre_tunnel_hw_if_indices[t->type]) > 0) {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100267 vnet_interface_main_t * im = &vnm->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268
Neale Ranns177bbdc2016-11-15 09:46:51 +0000269 hw_if_index = gm->free_gre_tunnel_hw_if_indices[t->type]
270 [vec_len (gm->free_gre_tunnel_hw_if_indices[t->type])-1];
271 _vec_len (gm->free_gre_tunnel_hw_if_indices[t->type]) -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100273 hi = vnet_get_hw_interface (vnm, hw_if_index);
274 hi->dev_instance = t - gm->tunnels;
275 hi->hw_instance = hi->dev_instance;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277 /* clear old stats of freed tunnel before reuse */
278 sw_if_index = hi->sw_if_index;
279 vnet_interface_counter_lock(im);
280 vlib_zero_combined_counter
Chris Luke27fe48f2016-04-28 13:44:38 -0400281 (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX], sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282 vlib_zero_combined_counter
Chris Luke27fe48f2016-04-28 13:44:38 -0400283 (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX], sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284 vlib_zero_simple_counter
Chris Luke27fe48f2016-04-28 13:44:38 -0400285 (&im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP], sw_if_index);
286 vnet_interface_counter_unlock(im);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000287 if (GRE_TUNNEL_TYPE_TEB == t->type)
Neale Ranns5e575b12016-10-03 09:40:25 +0100288 {
Neale Ranns177bbdc2016-11-15 09:46:51 +0000289 t->l2_tx_arc = vlib_node_add_named_next(vlib_get_main(),
290 hi->tx_node_index,
291 "adj-l2-midchain");
Neale Ranns5e575b12016-10-03 09:40:25 +0100292 }
Chris Luke27fe48f2016-04-28 13:44:38 -0400293 } else {
Neale Ranns177bbdc2016-11-15 09:46:51 +0000294 if (GRE_TUNNEL_TYPE_TEB == t->type)
David Hothama8cd3092016-09-19 09:55:07 -0700295 {
296 /* Default MAC address (d00b:eed0:0000 + sw_if_index) */
297 memset (address, 0, sizeof (address));
298 address[0] = 0xd0;
299 address[1] = 0x0b;
300 address[2] = 0xee;
301 address[3] = 0xd0;
302 address[4] = t - gm->tunnels;
303
Neale Rannsb80c5362016-10-08 13:03:40 +0100304 error = ethernet_register_interface(vnm,
Neale Ranns177bbdc2016-11-15 09:46:51 +0000305 gre_device_teb_class.index,
Neale Rannsb80c5362016-10-08 13:03:40 +0100306 t - gm->tunnels, address,
307 &hw_if_index,
308 0);
David Hothama8cd3092016-09-19 09:55:07 -0700309
310 if (error)
311 {
312 clib_error_report (error);
313 return VNET_API_ERROR_INVALID_REGISTRATION;
314 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100315 hi = vnet_get_hw_interface (vnm, hw_if_index);
316
317 t->l2_tx_arc = vlib_node_add_named_next(vlib_get_main(),
318 hi->tx_node_index,
319 "adj-l2-midchain");
David Hothama8cd3092016-09-19 09:55:07 -0700320 } else {
Neale Rannsb80c5362016-10-08 13:03:40 +0100321 hw_if_index = vnet_register_interface(vnm,
322 gre_device_class.index,
323 t - gm->tunnels,
324 gre_hw_interface_class.index,
325 t - gm->tunnels);
David Hothama8cd3092016-09-19 09:55:07 -0700326 }
327 hi = vnet_get_hw_interface (vnm, hw_if_index);
328 sw_if_index = hi->sw_if_index;
Chris Luke27fe48f2016-04-28 13:44:38 -0400329 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100331 t->hw_if_index = hw_if_index;
332 t->outer_fib_index = outer_fib_index;
333 t->sw_if_index = sw_if_index;
Neale Rannsad422ed2016-11-02 14:20:04 +0000334 t->l2_adj_index = ADJ_INDEX_INVALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100336 vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
337 gm->tunnel_index_by_sw_if_index[sw_if_index] = t - gm->tunnels;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100339 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Chris Luke71649002016-05-06 11:51:54 -0400340
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100341 hi->min_packet_bytes = 64 + sizeof (gre_header_t) + sizeof (ip4_header_t);
342 hi->per_packet_overhead_bytes =
Chris Luke27fe48f2016-04-28 13:44:38 -0400343 /* preamble */ 8 + /* inter frame gap */ 12;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100345 /* Standard default gre MTU. */
346 hi->max_l3_packet_bytes[VLIB_RX] = hi->max_l3_packet_bytes[VLIB_TX] = 9000;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100348 clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
349 clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100351 gre_tunnel_db_add(t);
Chris Luke27fe48f2016-04-28 13:44:38 -0400352
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100353 /*
354 * source the FIB entry for the tunnel's destination
355 * and become a child thereof. The tunnel will then get poked
356 * when the forwarding for the entry updates, and the tunnel can
357 * re-stack accordingly
358 */
359 const fib_prefix_t tun_dst_pfx = {
360 .fp_len = 32,
361 .fp_proto = FIB_PROTOCOL_IP4,
362 .fp_addr = {
363 .ip4 = t->tunnel_dst,
364 }
365 };
Chris Luke27fe48f2016-04-28 13:44:38 -0400366
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100367 t->fib_entry_index =
368 fib_table_entry_special_add(outer_fib_index,
369 &tun_dst_pfx,
370 FIB_SOURCE_RR,
371 FIB_ENTRY_FLAG_NONE,
372 ADJ_INDEX_INVALID);
373 t->sibling_index =
374 fib_entry_child_add(t->fib_entry_index,
375 FIB_NODE_TYPE_GRE_TUNNEL,
376 t - gm->tunnels);
Chris Luke27fe48f2016-04-28 13:44:38 -0400377
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100378 clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
379 clib_memcpy (&t->tunnel_dst, &a->dst, sizeof (t->tunnel_dst));
Neale Rannsb80c5362016-10-08 13:03:40 +0100380
Neale Ranns177bbdc2016-11-15 09:46:51 +0000381 if (GRE_TUNNEL_TYPE_TEB == t->type)
Neale Rannsb80c5362016-10-08 13:03:40 +0100382 {
383 t->l2_adj_index = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
Neale Ranns924d03a2016-10-19 08:25:46 +0100384 VNET_LINK_ETHERNET,
Neale Rannsb80c5362016-10-08 13:03:40 +0100385 &zero_addr,
386 sw_if_index);
Neale Rannsb80c5362016-10-08 13:03:40 +0100387 gre_update_adj(vnm, t->sw_if_index, t->l2_adj_index);
388 }
Chris Luke27fe48f2016-04-28 13:44:38 -0400389
390 if (sw_if_indexp)
391 *sw_if_indexp = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392
393 return 0;
394}
395
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100396static int
397vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t *a,
398 u32 * sw_if_indexp)
399{
400 gre_main_t * gm = &gre_main;
401 vnet_main_t * vnm = gm->vnet_main;
402 gre_tunnel_t * t;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100403 u32 sw_if_index;
404
405 t = gre_tunnel_db_find(&a->src, &a->dst, a->outer_fib_id);
406
407 if (NULL == t)
408 return VNET_API_ERROR_NO_SUCH_ENTRY;
409
410 sw_if_index = t->sw_if_index;
411 vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */);
412 /* make sure tunnel is removed from l2 bd or xconnect */
413 set_int_l2_mode(gm->vlib_main, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000414 vec_add1 (gm->free_gre_tunnel_hw_if_indices[t->type], t->hw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100415 gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
Neale Ranns177bbdc2016-11-15 09:46:51 +0000416
417 if (GRE_TUNNEL_TYPE_TEB == t->type)
418 adj_unlock(t->l2_adj_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100419
Neale Rannsad422ed2016-11-02 14:20:04 +0000420 if (t->l2_adj_index != ADJ_INDEX_INVALID)
421 adj_unlock(t->l2_adj_index);
422
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423 fib_entry_child_remove(t->fib_entry_index,
424 t->sibling_index);
425 fib_table_entry_delete_index(t->fib_entry_index,
426 FIB_SOURCE_RR);
427
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100428 gre_tunnel_db_remove(t);
429 fib_node_deinit(&t->node);
430 pool_put (gm->tunnels, t);
431
432 if (sw_if_indexp)
433 *sw_if_indexp = sw_if_index;
434
435 return 0;
436}
437
438int
439vnet_gre_add_del_tunnel (vnet_gre_add_del_tunnel_args_t *a,
440 u32 * sw_if_indexp)
441{
442 if (a->is_add)
443 return (vnet_gre_tunnel_add(a, sw_if_indexp));
444 else
445 return (vnet_gre_tunnel_delete(a, sw_if_indexp));
446}
447
Neale Rannsb80c5362016-10-08 13:03:40 +0100448clib_error_t *
449gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450{
Neale Rannsb80c5362016-10-08 13:03:40 +0100451 gre_main_t * gm = &gre_main;
452 vnet_hw_interface_t * hi;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100453 gre_tunnel_t *t;
Neale Rannsb80c5362016-10-08 13:03:40 +0100454 u32 ti;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100455
Neale Rannsb80c5362016-10-08 13:03:40 +0100456 hi = vnet_get_hw_interface (vnm, hw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100457
Neale Rannsb80c5362016-10-08 13:03:40 +0100458 if (NULL == gm->tunnel_index_by_sw_if_index ||
459 hi->sw_if_index >= vec_len(gm->tunnel_index_by_sw_if_index))
460 return (NULL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100461
Neale Rannsb80c5362016-10-08 13:03:40 +0100462 ti = gm->tunnel_index_by_sw_if_index[hi->sw_if_index];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100463
Neale Rannsb80c5362016-10-08 13:03:40 +0100464 if (~0 == ti)
465 /* not one of ours */
466 return (NULL);
467
468 t = pool_elt_at_index(gm->tunnels, ti);
469
470 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
471 vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100472 else
Neale Rannsb80c5362016-10-08 13:03:40 +0100473 vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100474
Neale Rannsb80c5362016-10-08 13:03:40 +0100475 gre_tunnel_restack(t);
476
477 return /* no error */ 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100478}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700479
480static clib_error_t *
481create_gre_tunnel_command_fn (vlib_main_t * vm,
482 unformat_input_t * input,
483 vlib_cli_command_t * cmd)
484{
485 unformat_input_t _line_input, * line_input = &_line_input;
Chris Luke27fe48f2016-04-28 13:44:38 -0400486 vnet_gre_add_del_tunnel_args_t _a, * a = &_a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 ip4_address_t src, dst;
488 u32 outer_fib_id = 0;
David Hothama8cd3092016-09-19 09:55:07 -0700489 u8 teb = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 u32 num_m_args = 0;
Chris Luke27fe48f2016-04-28 13:44:38 -0400492 u8 is_add = 1;
Pierre Pfister78ea9c22016-05-23 12:51:54 +0100493 u32 sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494
495 /* Get a line of input. */
496 if (! unformat_user (input, unformat_line_input, line_input))
497 return 0;
498
499 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
Chris Luke27fe48f2016-04-28 13:44:38 -0400500 if (unformat (line_input, "del"))
501 is_add = 0;
502 else if (unformat (line_input, "src %U", unformat_ip4_address, &src))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 num_m_args++;
504 else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst))
505 num_m_args++;
506 else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
507 ;
David Hothama8cd3092016-09-19 09:55:07 -0700508 else if (unformat (line_input, "teb"))
509 teb = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700510 else
511 return clib_error_return (0, "unknown input `%U'",
512 format_unformat_error, input);
513 }
514 unformat_free (line_input);
515
516 if (num_m_args < 2)
517 return clib_error_return (0, "mandatory argument(s) missing");
518
Chris Luke27fe48f2016-04-28 13:44:38 -0400519 if (memcmp (&src, &dst, sizeof(src)) == 0)
520 return clib_error_return (0, "src and dst are identical");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521
Chris Luke27fe48f2016-04-28 13:44:38 -0400522 memset (a, 0, sizeof (*a));
Hongjun Ni11bfc2f2016-07-22 18:19:19 +0800523 a->outer_fib_id = outer_fib_id;
David Hothama8cd3092016-09-19 09:55:07 -0700524 a->teb = teb;
Chris Luke27fe48f2016-04-28 13:44:38 -0400525 clib_memcpy(&a->src, &src, sizeof(src));
526 clib_memcpy(&a->dst, &dst, sizeof(dst));
527
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100528 if (is_add)
529 rv = vnet_gre_tunnel_add(a, &sw_if_index);
530 else
531 rv = vnet_gre_tunnel_delete(a, &sw_if_index);
Chris Luke27fe48f2016-04-28 13:44:38 -0400532
533 switch(rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 {
535 case 0:
Pierre Pfister78ea9c22016-05-23 12:51:54 +0100536 vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 break;
538 case VNET_API_ERROR_INVALID_VALUE:
539 return clib_error_return (0, "GRE tunnel already exists...");
540 case VNET_API_ERROR_NO_SUCH_FIB:
541 return clib_error_return (0, "outer fib ID %d doesn't exist\n",
542 outer_fib_id);
543 default:
Chris Luke27fe48f2016-04-28 13:44:38 -0400544 return clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 }
546
547 return 0;
548}
549
550VLIB_CLI_COMMAND (create_gre_tunnel_command, static) = {
551 .path = "create gre tunnel",
Chris Luke27fe48f2016-04-28 13:44:38 -0400552 .short_help = "create gre tunnel src <addr> dst <addr> "
David Hothama8cd3092016-09-19 09:55:07 -0700553 "[outer-fib-id <fib>] [teb] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 .function = create_gre_tunnel_command_fn,
555};
556
Chris Luke27fe48f2016-04-28 13:44:38 -0400557static clib_error_t *
558show_gre_tunnel_command_fn (vlib_main_t * vm,
559 unformat_input_t * input,
560 vlib_cli_command_t * cmd)
561{
562 gre_main_t * gm = &gre_main;
563 gre_tunnel_t * t;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100564 u32 ti = ~0;
Chris Luke27fe48f2016-04-28 13:44:38 -0400565
566 if (pool_elts (gm->tunnels) == 0)
567 vlib_cli_output (vm, "No GRE tunnels configured...");
568
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100569 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
570 {
571 if (unformat (input, "%d", &ti))
572 ;
573 else
574 break;
575 }
576
577 if (~0 == ti)
578 {
579 pool_foreach (t, gm->tunnels,
580 ({
Neale Rannsb80c5362016-10-08 13:03:40 +0100581 vlib_cli_output (vm, "%U", format_gre_tunnel, t);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100582 }));
583 }
584 else
585 {
586 t = pool_elt_at_index(gm->tunnels, ti);
587
Neale Rannsb80c5362016-10-08 13:03:40 +0100588 vlib_cli_output (vm, "%U", format_gre_tunnel, t);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100589 }
Chris Luke27fe48f2016-04-28 13:44:38 -0400590
591 return 0;
592}
593
594VLIB_CLI_COMMAND (show_gre_tunnel_command, static) = {
595 .path = "show gre tunnel",
596 .function = show_gre_tunnel_command_fn,
597};
598
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599/* force inclusion from application's main.c */
600clib_error_t *gre_interface_init (vlib_main_t *vm)
601{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100602 fib_node_register_type(FIB_NODE_TYPE_GRE_TUNNEL, &gre_vft);
603
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604 return 0;
605}
606VLIB_INIT_FUNCTION(gre_interface_init);