Merge tag 'upstream/1.2.4'
[quagga-debian.git] / nhrpd / nhrp_vty.c
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
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
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
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
193 static afi_t cmd_to_afi(const char *cmd)
194 {
195         return strncmp(cmd, "ipv6", 4) == 0 ? AFI_IP6 : AFI_IP;
196 }
197
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
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
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
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
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
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
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
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
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
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
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 }