1 /* NHRP vty handling
2  * Copyright (c) 2014-2015 Timo Teräs
3  *
4  * This file is free software: you may copy, redistribute and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  */
9 
10 #include "zebra.h"
11 #include "command.h"
12 #include "zclient.h"
13 #include "stream.h"
14 
15 #include "nhrpd.h"
16 #include "netlink.h"
17 
18 static struct cmd_node zebra_node = {
19 	.node   = ZEBRA_NODE,
20 	.prompt = "%s(config-router)# ",
21 	.vtysh  = 1,
22 };
23 
24 static struct cmd_node nhrp_interface_node = {
25 	.node   = INTERFACE_NODE,
26 	.prompt = "%s(config-if)# ",
27 	.vtysh  = 1,
28 };
29 
30 #define NHRP_DEBUG_FLAGS_CMD "(all|common|event|interface|kernel|route|vici)"
31 
32 #define NHRP_DEBUG_FLAGS_STR		\
33 	"All messages\n"		\
34 	"Common messages (default)\n"	\
35 	"Event manager messages\n"	\
36 	"Interface messages\n"		\
37 	"Kernel messages\n"		\
38 	"Route messages\n"		\
39 	"VICI messages\n"
40 
41 static const struct message debug_flags_desc[] = {
42 	{ NHRP_DEBUG_ALL, "all" },
43 	{ NHRP_DEBUG_COMMON, "common" },
44 	{ NHRP_DEBUG_IF, "interface" },
45 	{ NHRP_DEBUG_KERNEL, "kernel" },
46 	{ NHRP_DEBUG_ROUTE, "route" },
47 	{ NHRP_DEBUG_VICI, "vici" },
48 	{ NHRP_DEBUG_EVENT, "event" },
49 	{ 0, NULL },
50 };
51 
52 static const struct message interface_flags_desc[] = {
53 	{ NHRP_IFF_SHORTCUT, "shortcut" },
54 	{ NHRP_IFF_REDIRECT, "redirect" },
55 	{ NHRP_IFF_REG_NO_UNIQUE, "registration no-unique" },
56 	{ 0, NULL },
57 };
58 
nhrp_vty_return(struct vty * vty,int ret)59 static int nhrp_vty_return(struct vty *vty, int ret)
60 {
61 	static const char * const errmsgs[] = {
62 		[NHRP_ERR_FAIL]				= "Command failed",
63 		[NHRP_ERR_NO_MEMORY]			= "Out of memory",
64 		[NHRP_ERR_UNSUPPORTED_INTERFACE]	= "NHRP not supported on this interface",
65 		[NHRP_ERR_NHRP_NOT_ENABLED]		= "NHRP not enabled (set 'nhrp network-id' first)",
66 		[NHRP_ERR_ENTRY_EXISTS]			= "Entry exists already",
67 		[NHRP_ERR_ENTRY_NOT_FOUND]		= "Entry not found",
68 		[NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH]	= "Protocol address family does not match command (ip/ipv6 mismatch)",
69 	};
70 	const char *str = NULL;
71 	char buf[256];
72 
73 	if (ret == NHRP_OK)
74 		return CMD_SUCCESS;
75 
76 	if (ret > 0 && ret <= (int)ZEBRA_NUM_OF(errmsgs))
77 		if (errmsgs[ret])
78 			str = errmsgs[ret];
79 
80 	if (!str) {
81 		str = buf;
82 		snprintf(buf, sizeof(buf), "Unknown error %d", ret);
83 	}
84 
85 	vty_out (vty, "%% %s%s", str, VTY_NEWLINE);
86 
87 	return CMD_WARNING;
88 }
89 
toggle_flag(struct vty * vty,const struct message * flag_desc,const char * name,int on_off,unsigned * flags)90 static int toggle_flag(
91 	struct vty *vty, const struct message *flag_desc,
92 	const char *name, int on_off, unsigned *flags)
93 {
94 	int i;
95 
96 	for (i = 0; flag_desc[i].str != NULL; i++) {
97 		if (strcmp(flag_desc[i].str, name) != 0)
98 			continue;
99 		if (on_off)
100 			*flags |= flag_desc[i].key;
101 		else
102 			*flags &= ~flag_desc[i].key;
103 		return CMD_SUCCESS;
104 	}
105 
106 	vty_out(vty, "%% Invalid value %s%s", name, VTY_NEWLINE);
107 	return CMD_WARNING;
108 }
109 
110 #ifndef NO_DEBUG
111 
112 DEFUN(show_debugging_nhrp, show_debugging_nhrp_cmd,
113 	"show debugging nhrp",
114 	SHOW_STR
115 	"Debugging information\n"
116 	"NHRP configuration\n")
117 {
118 	int i;
119 
120 	vty_out(vty, "NHRP debugging status:%s", VTY_NEWLINE);
121 
122 	for (i = 0; debug_flags_desc[i].str != NULL; i++) {
123 		if (debug_flags_desc[i].key == NHRP_DEBUG_ALL)
124 			continue;
125 		if (!(debug_flags_desc[i].key & debug_flags))
126 			continue;
127 
128 		vty_out(vty, "  NHRP %s debugging is on%s",
129 			debug_flags_desc[i].str, VTY_NEWLINE);
130 	}
131 
132 	return CMD_SUCCESS;
133 }
134 
135 DEFUN(debug_nhrp, debug_nhrp_cmd,
136 	"debug nhrp " NHRP_DEBUG_FLAGS_CMD,
137 	"Enable debug messages for specific or all parts.\n"
138 	"NHRP information\n"
139 	NHRP_DEBUG_FLAGS_STR)
140 {
141 	return toggle_flag(vty, debug_flags_desc, argv[0], 1, &debug_flags);
142 }
143 
144 DEFUN(no_debug_nhrp, no_debug_nhrp_cmd,
145 	"no debug nhrp " NHRP_DEBUG_FLAGS_CMD,
146 	NO_STR
147 	"Disable debug messages for specific or all parts.\n"
148 	"NHRP information\n"
149 	NHRP_DEBUG_FLAGS_STR)
150 {
151 	return toggle_flag(vty, debug_flags_desc, argv[0], 0, &debug_flags);
152 }
153 
154 #endif /* NO_DEBUG */
155 
nhrp_config_write(struct vty * vty)156 static int nhrp_config_write(struct vty *vty)
157 {
158 #ifndef NO_DEBUG
159 	if (debug_flags == NHRP_DEBUG_ALL) {
160 		vty_out(vty, "debug nhrp all%s", VTY_NEWLINE);
161 	} else {
162 		int i;
163 
164 		for (i = 0; debug_flags_desc[i].str != NULL; i++) {
165 			if (debug_flags_desc[i].key == NHRP_DEBUG_ALL)
166 				continue;
167 			if (!(debug_flags & debug_flags_desc[i].key))
168 				continue;
169 			vty_out(vty, "debug nhrp %s%s", debug_flags_desc[i].str, VTY_NEWLINE);
170 		}
171 	}
172 	vty_out(vty, "!%s", VTY_NEWLINE);
173 #endif /* NO_DEBUG */
174 
175 	if (nhrp_event_socket_path) {
176 		vty_out(vty, "nhrp event socket %s%s",
177 			nhrp_event_socket_path, VTY_NEWLINE);
178 	}
179 	if (netlink_nflog_group) {
180 		vty_out(vty, "nhrp nflog-group %d%s",
181 			netlink_nflog_group, VTY_NEWLINE);
182 	}
183 
184 	return 0;
185 }
186 
187 #define IP_STR		"IP information\n"
188 #define IPV6_STR	"IPv6 information\n"
189 #define AFI_CMD		"(ip|ipv6)"
190 #define AFI_STR		IP_STR IPV6_STR
191 #define NHRP_STR	"Next Hop Resolution Protocol functions\n"
192 
cmd_to_afi(const char * cmd)193 static afi_t cmd_to_afi(const char *cmd)
194 {
195 	return strncmp(cmd, "ipv6", 4) == 0 ? AFI_IP6 : AFI_IP;
196 }
197 
afi_to_cmd(afi_t afi)198 static const char *afi_to_cmd(afi_t afi)
199 {
200 	if (afi == AFI_IP6) return "ipv6";
201 	return "ip";
202 }
203 
204 DEFUN(nhrp_event_socket, nhrp_event_socket_cmd,
205 	"nhrp event socket SOCKET",
206 	NHRP_STR
207 	"Event Manager commands\n"
208 	"Event Manager unix socket path\n"
209 	"Unix path for the socket\n")
210 {
211 	evmgr_set_socket(argv[0]);
212 	return CMD_SUCCESS;
213 }
214 
215 DEFUN(no_nhrp_event_socket, no_nhrp_event_socket_cmd,
216 	"no nhrp event socket [SOCKET]",
217 	NO_STR
218 	NHRP_STR
219 	"Event Manager commands\n"
220 	"Event Manager unix socket path\n"
221 	"Unix path for the socket\n")
222 {
223 	evmgr_set_socket(NULL);
224 	return CMD_SUCCESS;
225 }
226 
227 DEFUN(nhrp_nflog_group, nhrp_nflog_group_cmd,
228 	"nhrp nflog-group <1-65535>",
229 	NHRP_STR
230 	"Specify NFLOG group number\n"
231 	"NFLOG group number\n")
232 {
233 	uint32_t nfgroup;
234 
235 	VTY_GET_INTEGER_RANGE("nflog-group", nfgroup, argv[0], 1, 65535);
236 	netlink_set_nflog_group(nfgroup);
237 
238 	return CMD_SUCCESS;
239 }
240 
241 DEFUN(no_nhrp_nflog_group, no_nhrp_nflog_group_cmd,
242 	"no nhrp nflog-group [<1-65535>]",
243 	NO_STR
244 	NHRP_STR
245 	"Specify NFLOG group number\n"
246 	"NFLOG group number\n")
247 {
248 	netlink_set_nflog_group(0);
249 	return CMD_SUCCESS;
250 }
251 
252 DEFUN(tunnel_protection, tunnel_protection_cmd,
253 	"tunnel protection vici profile PROFILE {fallback-profile FALLBACK}",
254 	"NHRP/GRE integration\n"
255 	"IPsec protection\n"
256 	"VICI (StrongSwan)\n"
257 	"IPsec profile\n"
258 	"IPsec profile name\n"
259 	"Fallback IPsec profile\n"
260 	"Fallback IPsec profile name\n")
261 {
262 	struct interface *ifp = vty->index;
263 
264 	nhrp_interface_set_protection(ifp, argv[0], argv[1]);
265 	return CMD_SUCCESS;
266 }
267 
268 DEFUN(no_tunnel_protection, no_tunnel_protection_cmd,
269 	"no tunnel protection",
270 	NO_STR
271 	"NHRP/GRE integration\n"
272 	"IPsec protection\n")
273 {
274 	struct interface *ifp = vty->index;
275 
276 	nhrp_interface_set_protection(ifp, NULL, NULL);
277 	return CMD_SUCCESS;
278 }
279 
280 DEFUN(tunnel_source, tunnel_source_cmd,
281 	"tunnel source INTERFACE",
282 	"NHRP/GRE integration\n"
283 	"Tunnel device binding tracking\n"
284 	"Interface name\n")
285 {
286 	struct interface *ifp = vty->index;
287 	nhrp_interface_set_source(ifp, argv[0]);
288 	return CMD_SUCCESS;
289 }
290 
291 DEFUN(no_tunnel_source, no_tunnel_source_cmd,
292 	"no tunnel source",
293 	"NHRP/GRE integration\n"
294 	"Tunnel device binding tracking\n"
295 	"Interface name\n")
296 {
297 	struct interface *ifp = vty->index;
298 	nhrp_interface_set_source(ifp, NULL);
299 	return CMD_SUCCESS;
300 }
301 
302 DEFUN(if_nhrp_network_id, if_nhrp_network_id_cmd,
303 	AFI_CMD " nhrp network-id <1-4294967295>",
304 	AFI_STR
305 	NHRP_STR
306 	"Enable NHRP and specify network-id\n"
307 	"System local ID to specify interface group\n")
308 {
309 	struct interface *ifp = vty->index;
310 	struct nhrp_interface *nifp = ifp->info;
311 	afi_t afi = cmd_to_afi(argv[0]);
312 
313 	VTY_GET_INTEGER_RANGE("network-id", nifp->afi[afi].network_id, argv[1], 1, 4294967295);
314 	nhrp_interface_update(ifp);
315 
316 	return CMD_SUCCESS;
317 }
318 
319 DEFUN(if_no_nhrp_network_id, if_no_nhrp_network_id_cmd,
320 	"no " AFI_CMD " nhrp network-id [<1-4294967295>]",
321 	NO_STR
322 	AFI_STR
323 	NHRP_STR
324 	"Enable NHRP and specify network-id\n"
325 	"System local ID to specify interface group\n")
326 {
327 	struct interface *ifp = vty->index;
328 	struct nhrp_interface *nifp = ifp->info;
329 	afi_t afi = cmd_to_afi(argv[0]);
330 
331 	nifp->afi[afi].network_id = 0;
332 	nhrp_interface_update(ifp);
333 
334 	return CMD_SUCCESS;
335 }
336 
337 DEFUN(if_nhrp_flags, if_nhrp_flags_cmd,
338 	AFI_CMD " nhrp (shortcut|redirect)",
339 	AFI_STR
340 	NHRP_STR
341 	"Allow shortcut establishment\n"
342 	"Send redirect notifications\n")
343 {
344 	struct interface *ifp = vty->index;
345 	struct nhrp_interface *nifp = ifp->info;
346 	afi_t afi = cmd_to_afi(argv[0]);
347 
348 	return toggle_flag(vty, interface_flags_desc, argv[1], 1, &nifp->afi[afi].flags);
349 }
350 
351 DEFUN(if_no_nhrp_flags, if_no_nhrp_flags_cmd,
352 	"no " AFI_CMD " nhrp (shortcut|redirect)",
353 	NO_STR
354 	AFI_STR
355 	NHRP_STR
356 	"Allow shortcut establishment\n"
357 	"Send redirect notifications\n")
358 {
359 	struct interface *ifp = vty->index;
360 	struct nhrp_interface *nifp = ifp->info;
361 	afi_t afi = cmd_to_afi(argv[0]);
362 
363 	return toggle_flag(vty, interface_flags_desc, argv[1], 0, &nifp->afi[afi].flags);
364 }
365 
366 DEFUN(if_nhrp_reg_flags, if_nhrp_reg_flags_cmd,
367 	AFI_CMD " nhrp registration (no-unique)",
368 	AFI_STR
369 	NHRP_STR
370 	"Registration configuration\n"
371 	"Don't set unique flag\n")
372 {
373 	struct interface *ifp = vty->index;
374 	struct nhrp_interface *nifp = ifp->info;
375 	afi_t afi = cmd_to_afi(argv[0]);
376 	char name[256];
377 	snprintf(name, sizeof(name), "registration %s", argv[1]);
378 	return toggle_flag(vty, interface_flags_desc, name, 1, &nifp->afi[afi].flags);
379 }
380 
381 DEFUN(if_no_nhrp_reg_flags, if_no_nhrp_reg_flags_cmd,
382 	"no " AFI_CMD " nhrp registration (no-unique)",
383 	NO_STR
384 	AFI_STR
385 	NHRP_STR
386 	"Registration configuration\n"
387 	"Don't set unique flag\n")
388 {
389 	struct interface *ifp = vty->index;
390 	struct nhrp_interface *nifp = ifp->info;
391 	afi_t afi = cmd_to_afi(argv[0]);
392 	char name[256];
393 	snprintf(name, sizeof(name), "registration %s", argv[1]);
394 	return toggle_flag(vty, interface_flags_desc, name, 0, &nifp->afi[afi].flags);
395 }
396 
397 DEFUN(if_nhrp_holdtime, if_nhrp_holdtime_cmd,
398 	AFI_CMD " nhrp holdtime <1-65000>",
399 	AFI_STR
400 	NHRP_STR
401 	"Specify NBMA address validity time\n"
402 	"Time in seconds that NBMA addresses are advertised valid\n")
403 {
404 	struct interface *ifp = vty->index;
405 	struct nhrp_interface *nifp = ifp->info;
406 	afi_t afi = cmd_to_afi(argv[0]);
407 
408 	VTY_GET_INTEGER_RANGE("holdtime", nifp->afi[afi].holdtime, argv[1], 1, 65000);
409 	nhrp_interface_update(ifp);
410 
411 	return CMD_SUCCESS;
412 }
413 
414 DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd,
415 	"no " AFI_CMD " nhrp holdtime [1-65000]",
416 	NO_STR
417 	AFI_STR
418 	NHRP_STR
419 	"Specify NBMA address validity time\n"
420 	"Time in seconds that NBMA addresses are advertised valid\n")
421 {
422 	struct interface *ifp = vty->index;
423 	struct nhrp_interface *nifp = ifp->info;
424 	afi_t afi = cmd_to_afi(argv[0]);
425 
426 	nifp->afi[afi].holdtime = NHRPD_DEFAULT_HOLDTIME;
427 	nhrp_interface_update(ifp);
428 
429 	return CMD_SUCCESS;
430 }
431 
432 DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd,
433 	"ip nhrp mtu (<576-1500>|opennhrp)",
434 	IP_STR
435 	NHRP_STR
436 	"Configure NHRP advertised MTU\n"
437 	"MTU value\n"
438 	"Advertise bound interface MTU similar to OpenNHRP")
439 {
440 	struct interface *ifp = vty->index;
441 	struct nhrp_interface *nifp = ifp->info;
442 
443 	if (argv[0][0] == 'o') {
444 		nifp->afi[AFI_IP].configured_mtu = -1;
445 	} else {
446 		VTY_GET_INTEGER_RANGE("mtu", nifp->afi[AFI_IP].configured_mtu, argv[0], 576, 1500);
447 	}
448 	nhrp_interface_update_mtu(ifp, AFI_IP);
449 
450 	return CMD_SUCCESS;
451 }
452 
453 DEFUN(if_no_nhrp_mtu, if_no_nhrp_mtu_cmd,
454 	"no ip nhrp mtu [(<576-1500>|opennhrp)]",
455 	NO_STR
456 	IP_STR
457 	NHRP_STR
458 	"Configure NHRP advertised MTU\n"
459 	"MTU value\n"
460 	"Advertise bound interface MTU similar to OpenNHRP")
461 {
462 	struct interface *ifp = vty->index;
463 	struct nhrp_interface *nifp = ifp->info;
464 
465 	nifp->afi[AFI_IP].configured_mtu = 0;
466 	nhrp_interface_update_mtu(ifp, AFI_IP);
467 	return CMD_SUCCESS;
468 }
469 
470 DEFUN(if_nhrp_map, if_nhrp_map_cmd,
471 	AFI_CMD " nhrp map (A.B.C.D|X:X::X:X) (A.B.C.D|local)",
472 	AFI_STR
473 	NHRP_STR
474 	"Nexthop Server configuration\n"
475 	"IPv4 protocol address\n"
476 	"IPv6 protocol address\n"
477 	"IPv4 NBMA address\n"
478 	"Handle protocol address locally\n")
479 {
480 	struct interface *ifp = vty->index;
481 	afi_t afi = cmd_to_afi(argv[0]);
482 	union sockunion proto_addr, nbma_addr;
483 	struct nhrp_cache *c;
484 
485 	if (str2sockunion(argv[1], &proto_addr) < 0 ||
486 	    afi2family(afi) != sockunion_family(&proto_addr))
487 		return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
488 
489 	c = nhrp_cache_get(ifp, &proto_addr, 1);
490 	if (!c)
491 		return nhrp_vty_return(vty, NHRP_ERR_FAIL);
492 
493 	c->map = 1;
494 	if (strcmp(argv[2], "local") == 0) {
495 		nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL);
496 	} else{
497 		if (str2sockunion(argv[2], &nbma_addr) < 0)
498 			return nhrp_vty_return(vty, NHRP_ERR_FAIL);
499 		nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
500 			nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
501 	}
502 
503 	return CMD_SUCCESS;
504 }
505 
506 DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
507 	"no " AFI_CMD " nhrp map (A.B.C.D|X:X::X:X)",
508 	NO_STR
509 	AFI_STR
510 	NHRP_STR
511 	"Nexthop Server configuration\n"
512 	"IPv4 protocol address\n"
513 	"IPv6 protocol address\n")
514 {
515 	struct interface *ifp = vty->index;
516 	afi_t afi = cmd_to_afi(argv[0]);
517 	union sockunion proto_addr;
518 	struct nhrp_cache *c;
519 
520 	if (str2sockunion(argv[1], &proto_addr) < 0 ||
521 	    afi2family(afi) != sockunion_family(&proto_addr))
522 		return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
523 
524 	c = nhrp_cache_get(ifp, &proto_addr, 0);
525 	if (!c || !c->map)
526 		return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND);
527 
528 	nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
529 	return CMD_SUCCESS;
530 }
531 
532 DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd,
533 	AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)",
534 	AFI_STR
535 	NHRP_STR
536 	"Nexthop Server configuration\n"
537 	"IPv4 protocol address\n"
538 	"IPv6 protocol address\n"
539 	"Automatic detection of protocol address\n"
540 	"IPv4 NBMA address\n"
541 	"Fully qualified domain name for NBMA address(es)\n")
542 {
543 	struct interface *ifp = vty->index;
544 	afi_t afi = cmd_to_afi(argv[0]);
545 	union sockunion proto_addr;
546 	int ret;
547 
548 	if (str2sockunion(argv[1], &proto_addr) < 0)
549 		sockunion_family(&proto_addr) = AF_UNSPEC;
550 
551 	ret = nhrp_nhs_add(ifp, afi, &proto_addr, argv[2]);
552 	return nhrp_vty_return(vty, ret);
553 }
554 
555 DEFUN(if_no_nhrp_nhs, if_no_nhrp_nhs_cmd,
556 	"no " AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)",
557 	NO_STR
558 	AFI_STR
559 	NHRP_STR
560 	"Nexthop Server configuration\n"
561 	"IPv4 protocol address\n"
562 	"IPv6 protocol address\n"
563 	"Automatic detection of protocol address\n"
564 	"IPv4 NBMA address\n"
565 	"Fully qualified domain name for NBMA address(es)\n")
566 {
567 	struct interface *ifp = vty->index;
568 	afi_t afi = cmd_to_afi(argv[0]);
569 	union sockunion proto_addr;
570 	int ret;
571 
572 	if (str2sockunion(argv[1], &proto_addr) < 0)
573 		sockunion_family(&proto_addr) = AF_UNSPEC;
574 
575 	ret = nhrp_nhs_del(ifp, afi, &proto_addr, argv[2]);
576 	return nhrp_vty_return(vty, ret);
577 }
578 
579 struct info_ctx {
580 	struct vty *vty;
581 	afi_t afi;
582 	int count;
583 };
584 
show_ip_nhrp_cache(struct nhrp_cache * c,void * pctx)585 static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx)
586 {
587 	struct info_ctx *ctx = pctx;
588 	struct vty *vty = ctx->vty;
589 	char buf[2][SU_ADDRSTRLEN];
590 
591 	if (ctx->afi != family2afi(sockunion_family(&c->remote_addr)))
592 		return;
593 
594 	if (!ctx->count) {
595 		vty_out(vty, "%-8s %-8s %-24s %-24s %-6s %s%s",
596 			"Iface",
597 			"Type",
598 			"Protocol",
599 			"NBMA",
600 			"Flags",
601 			"Identity",
602 			VTY_NEWLINE);
603 	}
604 	ctx->count++;
605 
606 	vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %c%c%c    %s%s",
607 		c->ifp->name,
608 		nhrp_cache_type_str[c->cur.type],
609 		sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]),
610 		c->cur.peer ? sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]) : "-",
611 		c->used ? 'U' : ' ',
612 		c->t_timeout ? 'T' : ' ',
613 		c->t_auth ? 'A' : ' ',
614 		c->cur.peer ? c->cur.peer->vc->remote.id : "-",
615 		VTY_NEWLINE);
616 }
617 
show_ip_nhrp_nhs(struct nhrp_nhs * n,struct nhrp_registration * reg,void * pctx)618 static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg, void *pctx)
619 {
620 	struct info_ctx *ctx = pctx;
621 	struct vty *vty = ctx->vty;
622 	char buf[2][SU_ADDRSTRLEN];
623 
624 	if (!ctx->count) {
625 		vty_out(vty, "%-8s %-24s %-16s %-16s%s",
626 			"Iface",
627 			"FQDN",
628 			"NBMA",
629 			"Protocol",
630 			VTY_NEWLINE);
631 	}
632 	ctx->count++;
633 
634 	vty_out(vty, "%-8s %-24s %-16s %-16s%s",
635 		n->ifp->name,
636 		n->nbma_fqdn,
637 		(reg && reg->peer) ? sockunion2str(&reg->peer->vc->remote.nbma, buf[0], sizeof buf[0]) : "-",
638 		sockunion2str(reg ? &reg->proto_addr : &n->proto_addr, buf[1], sizeof buf[1]),
639 		VTY_NEWLINE);
640 }
641 
show_ip_nhrp_shortcut(struct nhrp_shortcut * s,void * pctx)642 static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx)
643 {
644 	struct info_ctx *ctx = pctx;
645 	struct nhrp_cache *c;
646 	struct vty *vty = ctx->vty;
647 	char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN];
648 
649 	if (!ctx->count) {
650 		vty_out(vty, "%-8s %-24s %-24s %s%s",
651 			"Type",
652 			"Prefix",
653 			"Via",
654 			"Identity",
655 			VTY_NEWLINE);
656 	}
657 	ctx->count++;
658 
659 	c = s->cache;
660 	vty_out(ctx->vty, "%-8s %-24s %-24s %s%s",
661 		nhrp_cache_type_str[s->type],
662 		prefix2str(s->p, buf1, sizeof buf1),
663 		c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "",
664 		(c && c->cur.peer) ? c->cur.peer->vc->remote.id : "",
665 		VTY_NEWLINE);
666 }
667 
show_ip_opennhrp_cache(struct nhrp_cache * c,void * pctx)668 static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx)
669 {
670 	struct info_ctx *ctx = pctx;
671 	struct vty *vty = ctx->vty;
672 	char buf[SU_ADDRSTRLEN];
673 
674 	if (ctx->afi != family2afi(sockunion_family(&c->remote_addr)))
675 		return;
676 
677 	vty_out(ctx->vty,
678 		"Type: %s%s"
679 		"Flags:%s%s%s"
680 		"Protocol-Address: %s/%zu%s",
681 		nhrp_cache_type_str[c->cur.type],
682 		VTY_NEWLINE,
683 		(c->cur.peer && c->cur.peer->online) ? " up": "",
684 		c->used ? " used": "",
685 		VTY_NEWLINE,
686 		sockunion2str(&c->remote_addr, buf, sizeof buf),
687 		8 * family2addrsize(sockunion_family(&c->remote_addr)),
688 		VTY_NEWLINE);
689 
690 	if (c->cur.peer) {
691 		vty_out(ctx->vty,
692 			"NBMA-Address: %s%s",
693 			sockunion2str(&c->cur.peer->vc->remote.nbma, buf, sizeof buf),
694 			VTY_NEWLINE);
695 	}
696 
697 	if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC) {
698 		vty_out(ctx->vty,
699 			"NBMA-NAT-OA-Address: %s%s",
700 			sockunion2str(&c->cur.remote_nbma_natoa, buf, sizeof buf),
701 			VTY_NEWLINE);
702 	}
703 
704 	vty_out(ctx->vty, "%s", VTY_NEWLINE);
705 }
706 
707 DEFUN(show_ip_nhrp, show_ip_nhrp_cmd,
708 	"show " AFI_CMD " nhrp (cache|nhs|shortcut|opennhrp|)",
709 	SHOW_STR
710 	AFI_STR
711 	"NHRP information\n"
712 	"Forwarding cache information\n"
713 	"Next hop server information\n"
714 	"Shortcut information\n"
715 	"opennhrpctl style cache dump\n")
716 {
717 	struct listnode *node;
718 	struct interface *ifp;
719 	struct info_ctx ctx = {
720 		.vty = vty,
721 		.afi = cmd_to_afi(argv[0]),
722 	};
723 
724 	if (!argv[1] || argv[1][0] == 'c') {
725 		for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
726 			nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx);
727 	} else if (argv[1][0] == 'n') {
728 		for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
729 			nhrp_nhs_foreach(ifp, ctx.afi, show_ip_nhrp_nhs, &ctx);
730 	} else if (argv[1][0] == 's') {
731 		nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx);
732 	} else {
733 		vty_out(vty, "Status: ok%s%s", VTY_NEWLINE, VTY_NEWLINE);
734 		ctx.count++;
735 		for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
736 			nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx);
737 	}
738 
739 	if (!ctx.count) {
740 		vty_out(vty, "%% No entries%s", VTY_NEWLINE);
741 		return CMD_WARNING;
742 	}
743 
744 	return CMD_SUCCESS;
745 }
746 
show_dmvpn_entry(struct nhrp_vc * vc,void * ctx)747 static void show_dmvpn_entry(struct nhrp_vc *vc, void *ctx)
748 {
749 	struct vty *vty = ctx;
750 	char buf[2][SU_ADDRSTRLEN];
751 
752 	vty_out(vty, "%-24s %-24s %c      %-4d %-24s%s",
753 		sockunion2str(&vc->local.nbma, buf[0], sizeof buf[0]),
754 		sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]),
755 		notifier_active(&vc->notifier_list) ? 'n' : ' ',
756 		vc->ipsec,
757 		vc->remote.id,
758 		VTY_NEWLINE);
759 }
760 
761 DEFUN(show_dmvpn, show_dmvpn_cmd,
762 	"show dmvpn",
763 	SHOW_STR
764 	"DMVPN information\n")
765 {
766 	vty_out(vty, "%-24s %-24s %-6s %-4s %-24s%s",
767 		"Src",
768 		"Dst",
769 		"Flags",
770 		"SAs",
771 		"Identity",
772 		VTY_NEWLINE);
773 
774 	nhrp_vc_foreach(show_dmvpn_entry, vty);
775 
776 	return CMD_SUCCESS;
777 }
778 
clear_nhrp_cache(struct nhrp_cache * c,void * data)779 static void clear_nhrp_cache(struct nhrp_cache *c, void *data)
780 {
781 	struct info_ctx *ctx = data;
782 	if (c->cur.type <= NHRP_CACHE_CACHED) {
783 		nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
784 		ctx->count++;
785 	}
786 }
787 
clear_nhrp_shortcut(struct nhrp_shortcut * s,void * data)788 static void clear_nhrp_shortcut(struct nhrp_shortcut *s, void *data)
789 {
790 	struct info_ctx *ctx = data;
791 	nhrp_shortcut_purge(s, 1);
792 	ctx->count++;
793 }
794 
795 DEFUN(clear_nhrp, clear_nhrp_cmd,
796 	"clear " AFI_CMD " nhrp (cache|shortcut)",
797 	CLEAR_STR
798 	AFI_STR
799 	NHRP_STR
800 	"Dynamic cache entries\n"
801 	"Shortcut entries\n")
802 {
803 	struct listnode *node;
804 	struct interface *ifp;
805 	struct info_ctx ctx = {
806 		.vty = vty,
807 		.afi = cmd_to_afi(argv[0]),
808 		.count = 0,
809 	};
810 
811 	if (!argv[1] || argv[1][0] == 'c') {
812 		for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
813 			nhrp_cache_foreach(ifp, clear_nhrp_cache, &ctx);
814 	} else {
815 		nhrp_shortcut_foreach(ctx.afi, clear_nhrp_shortcut, &ctx);
816 	}
817 
818 	if (!ctx.count) {
819 		vty_out(vty, "%% No entries%s", VTY_NEWLINE);
820 		return CMD_WARNING;
821 	}
822 
823 	vty_out(vty, "%% %d entries cleared%s", ctx.count, VTY_NEWLINE);
824 	return CMD_SUCCESS;
825 }
826 
827 struct write_map_ctx {
828 	struct vty *vty;
829 	int family;
830 	const char *aficmd;
831 };
832 
interface_config_write_nhrp_map(struct nhrp_cache * c,void * data)833 static void interface_config_write_nhrp_map(struct nhrp_cache *c, void *data)
834 {
835 	struct write_map_ctx *ctx = data;
836 	struct vty *vty = ctx->vty;
837 	char buf[2][SU_ADDRSTRLEN];
838 
839 	if (!c->map) return;
840 	if (sockunion_family(&c->remote_addr) != ctx->family) return;
841 
842 	vty_out(vty, " %s nhrp map %s %s%s",
843 		ctx->aficmd,
844 		sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]),
845 		c->cur.type == NHRP_CACHE_LOCAL ? "local" :
846 		sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]),
847 		VTY_NEWLINE);
848 }
849 
interface_config_write(struct vty * vty)850 static int interface_config_write(struct vty *vty)
851 {
852 	struct write_map_ctx mapctx;
853 	struct listnode *node;
854 	struct interface *ifp;
855 	struct nhrp_interface *nifp;
856 	struct nhrp_nhs *nhs;
857 	const char *aficmd;
858 	afi_t afi;
859 	char buf[SU_ADDRSTRLEN];
860 	int i;
861 
862 	for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) {
863 		vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE);
864 		if (ifp->desc)
865 			vty_out(vty, " description %s%s", ifp->desc, VTY_NEWLINE);
866 
867 		nifp = ifp->info;
868 		if (nifp->ipsec_profile) {
869 			vty_out(vty, " tunnel protection vici profile %s",
870 				nifp->ipsec_profile);
871 			if (nifp->ipsec_fallback_profile)
872 				vty_out(vty, " fallback-profile %s",
873 					nifp->ipsec_fallback_profile);
874 			vty_out(vty, "%s", VTY_NEWLINE);
875 		}
876 		if (nifp->source)
877 			vty_out(vty, " tunnel source %s%s",
878 				nifp->source, VTY_NEWLINE);
879 
880 		for (afi = 0; afi < AFI_MAX; afi++) {
881 			struct nhrp_afi_data *ad = &nifp->afi[afi];
882 
883 			aficmd = afi_to_cmd(afi);
884 
885 			if (ad->network_id)
886 				vty_out(vty, " %s nhrp network-id %u%s",
887 					aficmd, ad->network_id,
888 					VTY_NEWLINE);
889 
890 			if (ad->holdtime != NHRPD_DEFAULT_HOLDTIME)
891 				vty_out(vty, " %s nhrp holdtime %u%s",
892 					aficmd, ad->holdtime,
893 					VTY_NEWLINE);
894 
895 			if (ad->configured_mtu < 0)
896 				vty_out(vty, " %s nhrp mtu opennhrp%s",
897 					aficmd, VTY_NEWLINE);
898 			else if (ad->configured_mtu)
899 				vty_out(vty, " %s nhrp mtu %u%s",
900 					aficmd, ad->configured_mtu,
901 					VTY_NEWLINE);
902 
903 			for (i = 0; interface_flags_desc[i].str != NULL; i++) {
904 				if (!(ad->flags & interface_flags_desc[i].key))
905 					continue;
906 				vty_out(vty, " %s nhrp %s%s",
907 					aficmd, interface_flags_desc[i].str, VTY_NEWLINE);
908 			}
909 
910 			mapctx = (struct write_map_ctx) {
911 				.vty = vty,
912 				.family = afi2family(afi),
913 				.aficmd = aficmd,
914 			};
915 			nhrp_cache_foreach(ifp, interface_config_write_nhrp_map, &mapctx);
916 
917 			list_for_each_entry(nhs, &ad->nhslist_head, nhslist_entry) {
918 				vty_out(vty, " %s nhrp nhs %s nbma %s%s",
919 					aficmd,
920 					sockunion_family(&nhs->proto_addr) == AF_UNSPEC ? "dynamic" : sockunion2str(&nhs->proto_addr, buf, sizeof buf),
921 					nhs->nbma_fqdn,
922 					VTY_NEWLINE);
923 			}
924 		}
925 
926 		vty_out (vty, "!%s", VTY_NEWLINE);
927 	}
928 
929 	return 0;
930 }
931 
nhrp_config_init(void)932 void nhrp_config_init(void)
933 {
934 	install_node(&zebra_node, nhrp_config_write);
935 	install_default(ZEBRA_NODE);
936 
937 	/* global commands */
938 	install_element(VIEW_NODE, &show_debugging_nhrp_cmd);
939 	install_element(VIEW_NODE, &show_ip_nhrp_cmd);
940 	install_element(VIEW_NODE, &show_dmvpn_cmd);
941 	install_element(ENABLE_NODE, &show_debugging_nhrp_cmd);
942 	install_element(ENABLE_NODE, &show_ip_nhrp_cmd);
943 	install_element(ENABLE_NODE, &show_dmvpn_cmd);
944 	install_element(ENABLE_NODE, &clear_nhrp_cmd);
945 
946 	install_element(ENABLE_NODE, &debug_nhrp_cmd);
947 	install_element(ENABLE_NODE, &no_debug_nhrp_cmd);
948 
949 	install_element(CONFIG_NODE, &debug_nhrp_cmd);
950 	install_element(CONFIG_NODE, &no_debug_nhrp_cmd);
951 
952 	install_element(CONFIG_NODE, &nhrp_event_socket_cmd);
953 	install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd);
954 	install_element(CONFIG_NODE, &nhrp_nflog_group_cmd);
955 	install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd);
956 
957 	/* interface specific commands */
958 	install_node(&nhrp_interface_node, interface_config_write);
959 	install_default(INTERFACE_NODE);
960 
961 	install_element(CONFIG_NODE, &interface_cmd);
962 	install_element(CONFIG_NODE, &no_interface_cmd);
963 	install_element(INTERFACE_NODE, &interface_cmd);
964 	install_element(INTERFACE_NODE, &no_interface_cmd);
965 	install_element(INTERFACE_NODE, &tunnel_protection_cmd);
966 	install_element(INTERFACE_NODE, &no_tunnel_protection_cmd);
967 	install_element(INTERFACE_NODE, &tunnel_source_cmd);
968 	install_element(INTERFACE_NODE, &no_tunnel_source_cmd);
969 	install_element(INTERFACE_NODE, &if_nhrp_network_id_cmd);
970 	install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd);
971 	install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd);
972 	install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd);
973 	install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd);
974 	install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd);
975 	install_element(INTERFACE_NODE, &if_nhrp_flags_cmd);
976 	install_element(INTERFACE_NODE, &if_no_nhrp_flags_cmd);
977 	install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd);
978 	install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd);
979 	install_element(INTERFACE_NODE, &if_nhrp_map_cmd);
980 	install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd);
981 	install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd);
982 	install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd);
983 }
984