Line data Source code
1 : /*
2 : * Copyright (c) 2016 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:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
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.
14 : */
15 :
16 : /**
17 : * @file
18 : * @brief Common utility functions for LISP-GPE interfaces.
19 : *
20 : */
21 :
22 : #include <vppinfra/error.h>
23 : #include <vppinfra/hash.h>
24 : #include <vnet/vnet.h>
25 : #include <vnet/ip/ip.h>
26 : #include <vnet/udp/udp_inlines.h>
27 : #include <vnet/ethernet/ethernet.h>
28 : #include <lisp/lisp-gpe/lisp_gpe.h>
29 : #include <lisp/lisp-gpe/lisp_gpe_fwd_entry.h>
30 : #include <lisp/lisp-gpe/lisp_gpe_tenant.h>
31 : #include <lisp/lisp-gpe/lisp_gpe_adjacency.h>
32 : #include <vnet/adj/adj.h>
33 : #include <vnet/fib/fib_table.h>
34 : #include <vnet/fib/ip4_fib.h>
35 : #include <vnet/fib/ip6_fib.h>
36 : #include <lisp/lisp-cp/lisp_cp_dpo.h>
37 :
38 : /**
39 : * @brief The VLIB node arc/edge from the interface's TX node, to the L2
40 : * load-balanceing node. Which is where all packets go
41 : */
42 : static uword l2_arc_to_lb;
43 :
44 : #define foreach_lisp_gpe_tx_next \
45 : _(DROP, "error-drop") \
46 : _(IP4_LOOKUP, "ip4-lookup") \
47 : _(IP6_LOOKUP, "ip6-lookup")
48 :
49 : typedef enum
50 : {
51 : #define _(sym,str) LISP_GPE_TX_NEXT_##sym,
52 : foreach_lisp_gpe_tx_next
53 : #undef _
54 : LISP_GPE_TX_N_NEXT,
55 : } lisp_gpe_tx_next_t;
56 :
57 : typedef struct
58 : {
59 : u32 tunnel_index;
60 : } lisp_gpe_tx_trace_t;
61 :
62 : u8 *
63 1 : format_lisp_gpe_tx_trace (u8 * s, va_list * args)
64 : {
65 1 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66 1 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67 1 : lisp_gpe_tx_trace_t *t = va_arg (*args, lisp_gpe_tx_trace_t *);
68 :
69 1 : s = format (s, "LISP-GPE-TX: tunnel %d", t->tunnel_index);
70 1 : return s;
71 : }
72 :
73 : #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
74 :
75 : /**
76 : * @brief LISP-GPE interface TX (encap) function.
77 : * @node lisp_gpe_interface_tx
78 : *
79 : * The LISP-GPE interface TX (encap) function.
80 : *
81 : * Looks up the associated tunnel based on the adjacency hit in the SD FIB
82 : * and if the tunnel is multihomed it uses the flow hash to determine
83 : * sub-tunnel, and rewrite string, to be used to encapsulate the packet.
84 : *
85 : * @param[in] vm vlib_main_t corresponding to the current thread.
86 : * @param[in] node vlib_node_runtime_t data for this node.
87 : * @param[in] frame vlib_frame_t whose contents should be dispatched.
88 : *
89 : * @return number of vectors in frame.
90 : */
91 576 : VLIB_NODE_FN (lisp_tunnel_output)
92 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
93 : {
94 : u32 n_left_from, next_index, *from, *to_next;
95 :
96 1 : from = vlib_frame_vector_args (from_frame);
97 1 : n_left_from = from_frame->n_vectors;
98 :
99 1 : next_index = node->cached_next_index;
100 :
101 2 : while (n_left_from > 0)
102 : {
103 : u32 n_left_to_next;
104 :
105 1 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
106 :
107 2 : while (n_left_from > 0 && n_left_to_next > 0)
108 : {
109 : u32 bi0, adj_index0, next0;
110 : const ip_adjacency_t *adj0;
111 : const dpo_id_t *dpo0;
112 : vlib_buffer_t *b0;
113 :
114 1 : bi0 = from[0];
115 1 : to_next[0] = bi0;
116 1 : from += 1;
117 1 : to_next += 1;
118 1 : n_left_from -= 1;
119 1 : n_left_to_next -= 1;
120 :
121 1 : b0 = vlib_get_buffer (vm, bi0);
122 1 : b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
123 :
124 : /* Follow the DPO on which the midchain is stacked */
125 1 : adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
126 1 : adj0 = adj_get (adj_index0);
127 1 : dpo0 = &adj0->sub_type.midchain.next_dpo;
128 1 : next0 = dpo0->dpoi_next_node;
129 1 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
130 :
131 1 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
132 : {
133 1 : lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
134 : sizeof (*tr));
135 1 : tr->tunnel_index = adj_index0;
136 : }
137 1 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
138 : n_left_to_next, bi0, next0);
139 : }
140 :
141 1 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
142 : }
143 :
144 1 : return from_frame->n_vectors;
145 : }
146 :
147 96218 : VLIB_REGISTER_NODE (lisp_tunnel_output) = {
148 : .name = "lisp-tunnel-output",
149 : .vector_size = sizeof (u32),
150 : .format_trace = format_lisp_gpe_tx_trace,
151 : .sibling_of = "tunnel-output",
152 : };
153 :
154 : static u8 *
155 2 : format_lisp_gpe_name (u8 * s, va_list * args)
156 : {
157 2 : u32 dev_instance = va_arg (*args, u32);
158 2 : return format (s, "lisp_gpe%d", dev_instance);
159 : }
160 :
161 : /* *INDENT-OFF* */
162 6335 : VNET_DEVICE_CLASS (lisp_gpe_device_class) = {
163 : .name = "LISP_GPE",
164 : .format_device_name = format_lisp_gpe_name,
165 : };
166 : /* *INDENT-ON* */
167 :
168 : u8 *
169 0 : format_lisp_gpe_header_with_length (u8 * s, va_list * args)
170 : {
171 0 : lisp_gpe_header_t *h = va_arg (*args, lisp_gpe_header_t *);
172 0 : u32 max_header_bytes = va_arg (*args, u32);
173 : u32 header_bytes;
174 :
175 0 : header_bytes = sizeof (h[0]);
176 0 : if (max_header_bytes != 0 && header_bytes > max_header_bytes)
177 0 : return format (s, "lisp-gpe header truncated");
178 :
179 0 : s = format (s, "flags: ");
180 : #define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
181 0 : foreach_lisp_gpe_flag_bit;
182 : #undef _
183 :
184 0 : s = format (s, "\n ver_res %d res %d next_protocol %d iid %d(%x)",
185 0 : h->ver_res, h->res, h->next_protocol,
186 0 : clib_net_to_host_u32 (h->iid << 8),
187 0 : clib_net_to_host_u32 (h->iid << 8));
188 0 : return s;
189 : }
190 :
191 : /* *INDENT-OFF* */
192 4031 : VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
193 : .name = "LISP_GPE",
194 : .format_header = format_lisp_gpe_header_with_length,
195 : .build_rewrite = lisp_gpe_build_rewrite,
196 : .update_adjacency = lisp_gpe_update_adjacency,
197 : };
198 : /* *INDENT-ON* */
199 :
200 :
201 : typedef struct
202 : {
203 : u32 dpo_index;
204 : } l2_lisp_gpe_tx_trace_t;
205 :
206 : static u8 *
207 0 : format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args)
208 : {
209 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
210 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
211 0 : l2_lisp_gpe_tx_trace_t *t = va_arg (*args, l2_lisp_gpe_tx_trace_t *);
212 :
213 0 : s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->dpo_index);
214 0 : return s;
215 : }
216 :
217 : /**
218 : * @brief LISP-GPE interface TX (encap) function for L2 overlays.
219 : * @node l2_lisp_gpe_interface_tx
220 : *
221 : * The L2 LISP-GPE interface TX (encap) function.
222 : *
223 : * Uses bridge domain index, source and destination ethernet addresses to
224 : * lookup tunnel. If the tunnel is multihomed a flow has is used to determine
225 : * the sub-tunnel and therefore the rewrite string to be used to encapsulate
226 : * the packets.
227 : *
228 : * @param[in] vm vlib_main_t corresponding to the current thread.
229 : * @param[in] node vlib_node_runtime_t data for this node.
230 : * @param[in] frame vlib_frame_t whose contents should be dispatched.
231 : *
232 : * @return number of vectors in frame.
233 : */
234 : static uword
235 0 : l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
236 : vlib_frame_t * from_frame)
237 : {
238 : u32 n_left_from, next_index, *from, *to_next;
239 0 : lisp_gpe_main_t *lgm = &lisp_gpe_main;
240 0 : u32 thread_index = vm->thread_index;
241 0 : vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
242 :
243 0 : from = vlib_frame_vector_args (from_frame);
244 0 : n_left_from = from_frame->n_vectors;
245 :
246 0 : next_index = node->cached_next_index;
247 :
248 0 : while (n_left_from > 0)
249 : {
250 : u32 n_left_to_next;
251 :
252 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
253 :
254 0 : while (n_left_from > 0 && n_left_to_next > 0)
255 : {
256 : vlib_buffer_t *b0;
257 : u32 bi0, lbi0;
258 : ethernet_header_t *e0;
259 :
260 0 : bi0 = from[0];
261 0 : to_next[0] = bi0;
262 0 : from += 1;
263 0 : to_next += 1;
264 0 : n_left_from -= 1;
265 0 : n_left_to_next -= 1;
266 :
267 0 : b0 = vlib_get_buffer (vm, bi0);
268 0 : e0 = vlib_buffer_get_current (b0);
269 :
270 0 : vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC;
271 :
272 : /* lookup dst + src mac */
273 0 : lbi0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index,
274 0 : e0->src_address, e0->dst_address);
275 0 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = lbi0;
276 :
277 0 : vlib_increment_combined_counter (cm, thread_index, lbi0, 1,
278 : vlib_buffer_length_in_chain (vm,
279 : b0));
280 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
281 : {
282 0 : l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
283 : sizeof (*tr));
284 0 : tr->dpo_index = lbi0;
285 : }
286 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
287 : n_left_to_next, bi0, l2_arc_to_lb);
288 : }
289 :
290 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
291 : }
292 :
293 0 : return from_frame->n_vectors;
294 : }
295 :
296 : static u8 *
297 0 : format_l2_lisp_gpe_name (u8 * s, va_list * args)
298 : {
299 0 : u32 dev_instance = va_arg (*args, u32);
300 0 : return format (s, "l2_lisp_gpe%d", dev_instance);
301 : }
302 :
303 : /* *INDENT-OFF* */
304 6335 : VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = {
305 : .name = "L2_LISP_GPE",
306 : .format_device_name = format_l2_lisp_gpe_name,
307 : .format_tx_trace = format_l2_lisp_gpe_tx_trace,
308 : .tx_function = l2_lisp_gpe_interface_tx,
309 : };
310 : /* *INDENT-ON* */
311 :
312 : typedef struct
313 : {
314 : u32 dpo_index;
315 : } nsh_lisp_gpe_tx_trace_t;
316 :
317 : u8 *
318 0 : format_nsh_lisp_gpe_tx_trace (u8 * s, va_list * args)
319 : {
320 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
321 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
322 0 : nsh_lisp_gpe_tx_trace_t *t = va_arg (*args, nsh_lisp_gpe_tx_trace_t *);
323 :
324 0 : s = format (s, "NSH-GPE-TX: tunnel %d", t->dpo_index);
325 0 : return s;
326 : }
327 :
328 : /**
329 : * @brief LISP-GPE interface TX for NSH overlays.
330 : * @node nsh_lisp_gpe_interface_tx
331 : *
332 : * The NSH LISP-GPE interface TX function.
333 : *
334 : * @param[in] vm vlib_main_t corresponding to the current thread.
335 : * @param[in] node vlib_node_runtime_t data for this node.
336 : * @param[in] frame vlib_frame_t whose contents should be dispatched.
337 : *
338 : * @return number of vectors in frame.
339 : */
340 : static uword
341 0 : nsh_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
342 : vlib_frame_t * from_frame)
343 : {
344 : u32 n_left_from, next_index, *from, *to_next;
345 0 : lisp_gpe_main_t *lgm = &lisp_gpe_main;
346 :
347 0 : from = vlib_frame_vector_args (from_frame);
348 0 : n_left_from = from_frame->n_vectors;
349 :
350 0 : next_index = node->cached_next_index;
351 :
352 0 : while (n_left_from > 0)
353 : {
354 : u32 n_left_to_next;
355 :
356 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
357 :
358 0 : while (n_left_from > 0 && n_left_to_next > 0)
359 : {
360 : vlib_buffer_t *b0;
361 : u32 bi0;
362 : u32 *nsh0, next0;
363 : const dpo_id_t *dpo0;
364 :
365 0 : bi0 = from[0];
366 0 : to_next[0] = bi0;
367 0 : from += 1;
368 0 : to_next += 1;
369 0 : n_left_from -= 1;
370 0 : n_left_to_next -= 1;
371 :
372 0 : b0 = vlib_get_buffer (vm, bi0);
373 0 : nsh0 = vlib_buffer_get_current (b0);
374 :
375 0 : vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_LCAF;
376 :
377 : /* lookup SPI + SI (second word of the NSH header).
378 : * NB: Load balancing was done by the control plane */
379 0 : dpo0 = lisp_nsh_fib_lookup (lgm, nsh0[1]);
380 :
381 0 : next0 = dpo0->dpoi_next_node;
382 0 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
383 :
384 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
385 : {
386 0 : nsh_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
387 : sizeof (*tr));
388 0 : tr->dpo_index = dpo0->dpoi_index;
389 : }
390 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
391 : n_left_to_next, bi0, next0);
392 : }
393 :
394 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
395 : }
396 :
397 0 : return from_frame->n_vectors;
398 : }
399 :
400 : static u8 *
401 0 : format_nsh_lisp_gpe_name (u8 * s, va_list * args)
402 : {
403 0 : u32 dev_instance = va_arg (*args, u32);
404 0 : return format (s, "nsh_lisp_gpe%d", dev_instance);
405 : }
406 :
407 : /* *INDENT-OFF* */
408 6335 : VNET_DEVICE_CLASS (nsh_lisp_gpe_device_class,static) = {
409 : .name = "NSH_LISP_GPE",
410 : .format_device_name = format_nsh_lisp_gpe_name,
411 : .format_tx_trace = format_nsh_lisp_gpe_tx_trace,
412 : .tx_function = nsh_lisp_gpe_interface_tx,
413 : };
414 : /* *INDENT-ON* */
415 :
416 : static vnet_hw_interface_t *
417 1 : lisp_gpe_create_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table,
418 : vnet_device_class_t * dev_class,
419 : tunnel_lookup_t * tuns)
420 : {
421 : u32 flen;
422 1 : u32 hw_if_index = ~0;
423 : u8 *new_name;
424 : vnet_hw_interface_t *hi;
425 1 : vnet_main_t *vnm = lgm->vnet_main;
426 :
427 : /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
428 1 : flen = vec_len (lgm->free_tunnel_hw_if_indices);
429 1 : if (flen > 0)
430 : {
431 0 : hw_if_index = lgm->free_tunnel_hw_if_indices[flen - 1];
432 0 : vec_dec_len (lgm->free_tunnel_hw_if_indices, 1);
433 :
434 0 : hi = vnet_get_hw_interface (vnm, hw_if_index);
435 :
436 : /* rename interface */
437 0 : new_name = format (0, "%U", dev_class->format_device_name, vni);
438 :
439 0 : vec_add1 (new_name, 0);
440 0 : vnet_rename_interface (vnm, hw_if_index, (char *) new_name);
441 0 : vec_free (new_name);
442 :
443 : /* clear old stats of freed interface before reuse */
444 0 : vnet_interface_main_t *im = &vnm->interface_main;
445 0 : vnet_interface_counter_lock (im);
446 0 : vlib_zero_combined_counter (&im->combined_sw_if_counters
447 : [VNET_INTERFACE_COUNTER_TX],
448 : hi->sw_if_index);
449 0 : vlib_zero_combined_counter (&im->combined_sw_if_counters
450 : [VNET_INTERFACE_COUNTER_RX],
451 : hi->sw_if_index);
452 0 : vlib_zero_simple_counter (&im->sw_if_counters
453 : [VNET_INTERFACE_COUNTER_DROP],
454 : hi->sw_if_index);
455 0 : vnet_interface_counter_unlock (im);
456 : }
457 : else
458 : {
459 1 : hw_if_index = vnet_register_interface (vnm, dev_class->index, vni,
460 : lisp_gpe_hw_class.index, 0);
461 1 : hi = vnet_get_hw_interface (vnm, hw_if_index);
462 : }
463 :
464 1 : hash_set (tuns->hw_if_index_by_dp_table, dp_table, hw_if_index);
465 :
466 : /* set tunnel termination: post decap, packets are tagged as having been
467 : * originated by lisp-gpe interface */
468 1 : hash_set (tuns->sw_if_index_by_vni, vni, hi->sw_if_index);
469 1 : hash_set (tuns->vni_by_sw_if_index, hi->sw_if_index, vni);
470 :
471 1 : return hi;
472 : }
473 :
474 : static void
475 0 : lisp_gpe_remove_iface (lisp_gpe_main_t * lgm, u32 hi_index, u32 dp_table,
476 : tunnel_lookup_t * tuns)
477 : {
478 0 : vnet_main_t *vnm = lgm->vnet_main;
479 : vnet_hw_interface_t *hi;
480 : uword *vnip;
481 :
482 0 : hi = vnet_get_hw_interface (vnm, hi_index);
483 :
484 : /* disable interface */
485 0 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0 /* down */ );
486 0 : vnet_hw_interface_set_flags (vnm, hi->hw_if_index, 0 /* down */ );
487 0 : hash_unset (tuns->hw_if_index_by_dp_table, dp_table);
488 0 : vec_add1 (lgm->free_tunnel_hw_if_indices, hi->hw_if_index);
489 :
490 : /* clean tunnel termination and vni to sw_if_index binding */
491 0 : vnip = hash_get (tuns->vni_by_sw_if_index, hi->sw_if_index);
492 0 : if (0 == vnip)
493 : {
494 0 : clib_warning ("No vni associated to interface %d", hi->sw_if_index);
495 0 : return;
496 : }
497 0 : hash_unset (tuns->sw_if_index_by_vni, vnip[0]);
498 0 : hash_unset (tuns->vni_by_sw_if_index, hi->sw_if_index);
499 : }
500 :
501 : static void
502 1 : lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id)
503 : {
504 : fib_node_index_t fib_index;
505 :
506 1 : fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id,
507 : FIB_SOURCE_LISP);
508 1 : ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
509 1 : ip4_sw_interface_enable_disable (sw_if_index, 1);
510 :
511 1 : fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, table_id,
512 : FIB_SOURCE_LISP);
513 1 : ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
514 1 : ip6_sw_interface_enable_disable (sw_if_index, 1);
515 1 : }
516 :
517 : static void
518 0 : lisp_gpe_tenant_del_default_routes (u32 table_id)
519 : {
520 : fib_protocol_t proto;
521 :
522 0 : FOR_EACH_FIB_IP_PROTOCOL (proto)
523 : {
524 0 : fib_prefix_t prefix = {
525 : .fp_proto = proto,
526 : };
527 : u32 fib_index;
528 :
529 0 : fib_index = fib_table_find (prefix.fp_proto, table_id);
530 0 : fib_table_entry_special_remove (fib_index, &prefix, FIB_SOURCE_LISP);
531 0 : fib_table_unlock (fib_index, prefix.fp_proto, FIB_SOURCE_LISP);
532 : }
533 0 : }
534 :
535 : static void
536 1 : lisp_gpe_tenant_add_default_routes (u32 table_id)
537 : {
538 : fib_protocol_t proto;
539 :
540 3 : FOR_EACH_FIB_IP_PROTOCOL (proto)
541 : {
542 2 : fib_prefix_t prefix = {
543 : .fp_proto = proto,
544 : };
545 : u32 fib_index;
546 :
547 : /*
548 : * Add a deafult route that results in a control plane punt DPO
549 : */
550 2 : fib_index = fib_table_find_or_create_and_lock (prefix.fp_proto, table_id,
551 : FIB_SOURCE_LISP);
552 2 : fib_table_entry_special_dpo_add (fib_index, &prefix, FIB_SOURCE_LISP,
553 : FIB_ENTRY_FLAG_EXCLUSIVE,
554 2 : lisp_cp_dpo_get (fib_proto_to_dpo
555 : (proto)));
556 : }
557 1 : }
558 :
559 :
560 : /**
561 : * @brief Add/del LISP-GPE L3 interface.
562 : *
563 : * Creates LISP-GPE interface, sets ingress arcs from lisp_gpeX_lookup,
564 : * installs default routes that attract all traffic with no more specific
565 : * routes to lgpe-ipx-lookup, set egress arcs to ipx-lookup, sets
566 : * the interface in the right vrf and enables it.
567 : *
568 : * @param[in] lgm Reference to @ref lisp_gpe_main_t.
569 : * @param[in] a Parameters to create interface.
570 : *
571 : * @return number of vectors in frame.
572 : */
573 : u32
574 1 : lisp_gpe_add_l3_iface (lisp_gpe_main_t * lgm, u32 vni, u32 table_id,
575 : u8 with_default_routes)
576 : {
577 1 : vnet_main_t *vnm = lgm->vnet_main;
578 1 : tunnel_lookup_t *l3_ifaces = &lgm->l3_ifaces;
579 : vnet_hw_interface_t *hi;
580 : uword *hip, *si;
581 :
582 1 : hip = hash_get (l3_ifaces->hw_if_index_by_dp_table, table_id);
583 :
584 1 : if (hip)
585 : {
586 0 : clib_warning ("vrf %d already mapped to a vni", table_id);
587 0 : return ~0;
588 : }
589 :
590 1 : si = hash_get (l3_ifaces->sw_if_index_by_vni, vni);
591 :
592 1 : if (si)
593 : {
594 0 : clib_warning ("Interface for vni %d already exists", vni);
595 : }
596 :
597 : /* create lisp iface and populate tunnel tables */
598 1 : hi = lisp_gpe_create_iface (lgm, vni, table_id,
599 : &lisp_gpe_device_class, l3_ifaces);
600 :
601 : /* insert default routes that point to lisp-cp lookup */
602 1 : lisp_gpe_iface_set_table (hi->sw_if_index, table_id);
603 1 : if (with_default_routes)
604 1 : lisp_gpe_tenant_add_default_routes (table_id);
605 :
606 : /* enable interface */
607 1 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
608 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
609 1 : vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
610 : VNET_HW_INTERFACE_FLAG_LINK_UP);
611 :
612 1 : return (hi->sw_if_index);
613 : }
614 :
615 : void
616 0 : lisp_gpe_del_l3_iface (lisp_gpe_main_t * lgm, u32 vni, u32 table_id)
617 : {
618 0 : vnet_main_t *vnm = lgm->vnet_main;
619 0 : tunnel_lookup_t *l3_ifaces = &lgm->l3_ifaces;
620 : vnet_hw_interface_t *hi;
621 : uword *hip;
622 :
623 0 : hip = hash_get (l3_ifaces->hw_if_index_by_dp_table, table_id);
624 :
625 0 : if (hip == 0)
626 : {
627 0 : clib_warning ("The interface for vrf %d doesn't exist", table_id);
628 0 : return;
629 : }
630 :
631 0 : hi = vnet_get_hw_interface (vnm, hip[0]);
632 :
633 0 : lisp_gpe_remove_iface (lgm, hip[0], table_id, &lgm->l3_ifaces);
634 :
635 : /* unset default routes */
636 0 : ip4_sw_interface_enable_disable (hi->sw_if_index, 0);
637 0 : ip6_sw_interface_enable_disable (hi->sw_if_index, 0);
638 0 : lisp_gpe_tenant_del_default_routes (table_id);
639 : }
640 :
641 : /**
642 : * @brief Add/del LISP-GPE L2 interface.
643 : *
644 : * Creates LISP-GPE interface, sets it in L2 mode in the appropriate
645 : * bridge domain, sets egress arcs and enables it.
646 : *
647 : * @param[in] lgm Reference to @ref lisp_gpe_main_t.
648 : * @param[in] a Parameters to create interface.
649 : *
650 : * @return number of vectors in frame.
651 : */
652 : u32
653 0 : lisp_gpe_add_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
654 : {
655 0 : vnet_main_t *vnm = lgm->vnet_main;
656 0 : tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces;
657 : vnet_hw_interface_t *hi;
658 : uword *hip, *si;
659 : u16 bd_index;
660 :
661 0 : if (bd_id > L2_BD_ID_MAX)
662 : {
663 0 : clib_warning ("bridge domain ID %d exceed 16M limit", bd_id);
664 0 : return ~0;
665 : }
666 :
667 0 : bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
668 0 : hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index);
669 :
670 0 : if (hip)
671 : {
672 0 : clib_warning ("bridge domain %d already mapped to a vni", bd_id);
673 0 : return ~0;
674 : }
675 :
676 0 : si = hash_get (l2_ifaces->sw_if_index_by_vni, vni);
677 0 : if (si)
678 : {
679 0 : clib_warning ("Interface for vni %d already exists", vni);
680 0 : return ~0;
681 : }
682 :
683 : /* create lisp iface and populate tunnel tables */
684 0 : hi = lisp_gpe_create_iface (lgm, vni, bd_index,
685 : &l2_lisp_gpe_device_class, &lgm->l2_ifaces);
686 :
687 : /* enable interface */
688 0 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
689 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
690 0 : vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
691 : VNET_HW_INTERFACE_FLAG_LINK_UP);
692 :
693 0 : l2_arc_to_lb = vlib_node_add_named_next (vlib_get_main (),
694 0 : hi->tx_node_index,
695 : "l2-load-balance");
696 :
697 : /* we're ready. add iface to l2 bridge domain */
698 0 : set_int_l2_mode (lgm->vlib_main, vnm, MODE_L2_BRIDGE, hi->sw_if_index,
699 : bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
700 :
701 0 : return (hi->sw_if_index);
702 : }
703 :
704 : /**
705 : * @brief Add/del LISP-GPE L2 interface.
706 : *
707 : * Creates LISP-GPE interface, sets it in L2 mode in the appropriate
708 : * bridge domain, sets egress arcs and enables it.
709 : *
710 : * @param[in] lgm Reference to @ref lisp_gpe_main_t.
711 : * @param[in] a Parameters to create interface.
712 : *
713 : * @return number of vectors in frame.
714 : */
715 : void
716 0 : lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
717 : {
718 0 : tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces;
719 : vnet_hw_interface_t *hi;
720 :
721 0 : u32 bd_index = bd_find_index (&bd_main, bd_id);
722 0 : ASSERT (bd_index != ~0);
723 0 : uword *hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index);
724 :
725 0 : if (hip == 0)
726 : {
727 0 : clib_warning ("The interface for bridge domain %d doesn't exist",
728 : bd_id);
729 0 : return;
730 : }
731 :
732 : /* Remove interface from bridge .. by enabling L3 mode */
733 0 : hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]);
734 0 : set_int_l2_mode (lgm->vlib_main, lgm->vnet_main, MODE_L3, hi->sw_if_index,
735 : 0, L2_BD_PORT_TYPE_NORMAL, 0, 0);
736 0 : lisp_gpe_remove_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces);
737 : }
738 :
739 : /**
740 : * @brief Add LISP-GPE NSH interface.
741 : *
742 : * Creates LISP-GPE interface, sets it in L3 mode.
743 : *
744 : * @param[in] lgm Reference to @ref lisp_gpe_main_t.
745 : * @param[in] a Parameters to create interface.
746 : *
747 : * @return sw_if_index.
748 : */
749 : u32
750 0 : vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm)
751 : {
752 0 : vnet_main_t *vnm = lgm->vnet_main;
753 0 : tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
754 : vnet_hw_interface_t *hi;
755 : uword *hip, *si;
756 :
757 0 : hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
758 :
759 0 : if (hip)
760 : {
761 0 : clib_warning ("NSH interface 0 already exists");
762 0 : return ~0;
763 : }
764 :
765 0 : si = hash_get (nsh_ifaces->sw_if_index_by_vni, 0);
766 0 : if (si)
767 : {
768 0 : clib_warning ("NSH interface already exists");
769 0 : return ~0;
770 : }
771 :
772 : /* create lisp iface and populate tunnel tables */
773 0 : hi = lisp_gpe_create_iface (lgm, 0, 0,
774 : &nsh_lisp_gpe_device_class, &lgm->nsh_ifaces);
775 :
776 : /* enable interface */
777 0 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
778 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
779 0 : vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
780 : VNET_HW_INTERFACE_FLAG_LINK_UP);
781 :
782 0 : return (hi->sw_if_index);
783 : }
784 :
785 : /**
786 : * @brief Del LISP-GPE NSH interface.
787 : *
788 : */
789 : void
790 0 : vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm)
791 : {
792 0 : tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
793 : uword *hip;
794 :
795 0 : hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
796 :
797 0 : if (hip == 0)
798 : {
799 0 : clib_warning ("The NSH 0 interface doesn't exist");
800 0 : return;
801 : }
802 0 : lisp_gpe_remove_iface (lgm, hip[0], 0, &lgm->nsh_ifaces);
803 : }
804 :
805 : static clib_error_t *
806 0 : lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
807 : vlib_cli_command_t * cmd)
808 : {
809 0 : unformat_input_t _line_input, *line_input = &_line_input;
810 0 : u8 is_add = 1;
811 : u32 table_id, vni, bd_id;
812 0 : u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0;
813 0 : u8 nsh_iface = 0;
814 0 : clib_error_t *error = NULL;
815 :
816 0 : if (vnet_lisp_gpe_enable_disable_status () == 0)
817 : {
818 0 : return clib_error_return (0, "LISP is disabled");
819 : }
820 :
821 : /* Get a line of input. */
822 0 : if (!unformat_user (input, unformat_line_input, line_input))
823 0 : return 0;
824 :
825 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
826 : {
827 0 : if (unformat (line_input, "add"))
828 0 : is_add = 1;
829 0 : else if (unformat (line_input, "del"))
830 0 : is_add = 0;
831 0 : else if (unformat (line_input, "vrf %d", &table_id))
832 : {
833 0 : vrf_is_set = 1;
834 : }
835 0 : else if (unformat (line_input, "vni %d", &vni))
836 : {
837 0 : vni_is_set = 1;
838 : }
839 0 : else if (unformat (line_input, "bd %d", &bd_id))
840 : {
841 0 : bd_index_is_set = 1;
842 : }
843 0 : else if (unformat (line_input, "nsh"))
844 : {
845 0 : nsh_iface = 1;
846 : }
847 : else
848 : {
849 0 : error = clib_error_return (0, "parse error: '%U'",
850 : format_unformat_error, line_input);
851 0 : goto done;
852 : }
853 : }
854 :
855 0 : if (nsh_iface)
856 : {
857 0 : if (is_add)
858 : {
859 0 : if (~0 == vnet_lisp_gpe_add_nsh_iface (&lisp_gpe_main))
860 : {
861 0 : error = clib_error_return (0, "NSH interface not created");
862 0 : goto done;
863 : }
864 : }
865 : else
866 : {
867 0 : vnet_lisp_gpe_del_nsh_iface (&lisp_gpe_main);
868 : }
869 0 : goto done;
870 : }
871 :
872 0 : if (vrf_is_set && bd_index_is_set)
873 : {
874 0 : error = clib_error_return
875 : (0, "Cannot set both vrf and brdige domain index!");
876 0 : goto done;
877 : }
878 :
879 0 : if (!vni_is_set)
880 : {
881 0 : error = clib_error_return (0, "vni must be set!");
882 0 : goto done;
883 : }
884 :
885 0 : if (!vrf_is_set && !bd_index_is_set)
886 : {
887 : error =
888 0 : clib_error_return (0, "vrf or bridge domain index must be set!");
889 0 : goto done;
890 : }
891 :
892 0 : if (bd_index_is_set)
893 : {
894 0 : if (is_add)
895 : {
896 0 : if (~0 == lisp_gpe_tenant_l2_iface_add_or_lock (vni, bd_id))
897 : {
898 0 : error = clib_error_return (0, "L2 interface not created");
899 0 : goto done;
900 : }
901 : }
902 : else
903 0 : lisp_gpe_tenant_l2_iface_unlock (vni);
904 : }
905 : else
906 : {
907 0 : if (is_add)
908 : {
909 0 : if (~0 == lisp_gpe_tenant_l3_iface_add_or_lock (vni, table_id, 1
910 : /* with_default_route */
911 : ))
912 : {
913 0 : error = clib_error_return (0, "L3 interface not created");
914 0 : goto done;
915 : }
916 : }
917 : else
918 0 : lisp_gpe_tenant_l3_iface_unlock (vni);
919 : }
920 :
921 0 : done:
922 0 : unformat_free (line_input);
923 :
924 0 : return error;
925 : }
926 :
927 : /* *INDENT-OFF* */
928 123991 : VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
929 : .path = "gpe iface",
930 : .short_help = "gpe iface add/del vni <vni> vrf <vrf>",
931 : .function = lisp_gpe_add_del_iface_command_fn,
932 : };
933 : /* *INDENT-ON* */
934 :
935 : /*
936 : * fd.io coding-style-patch-verification: ON
937 : *
938 : * Local Variables:
939 : * eval: (c-set-style "gnu")
940 : * End:
941 : */
|