summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/eigrpctl/Makefile16
-rw-r--r--usr.sbin/eigrpctl/eigrpctl.8142
-rw-r--r--usr.sbin/eigrpctl/eigrpctl.c782
-rw-r--r--usr.sbin/eigrpctl/parser.c454
-rw-r--r--usr.sbin/eigrpctl/parser.h62
5 files changed, 1456 insertions, 0 deletions
diff --git a/usr.sbin/eigrpctl/Makefile b/usr.sbin/eigrpctl/Makefile
new file mode 100644
index 00000000000..60b1a7dd966
--- /dev/null
+++ b/usr.sbin/eigrpctl/Makefile
@@ -0,0 +1,16 @@
+# $OpenBSD: Makefile,v 1.1 2015/10/02 04:31:52 renato Exp $
+
+.PATH: ${.CURDIR}/../eigrpd
+
+PROG= eigrpctl
+SRCS= util.c log.c eigrpctl.c parser.c
+CFLAGS+= -Wall
+CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../eigrpd
+LDADD= -lutil
+DPADD= ${LIBUTIL}
+MAN= eigrpctl.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/eigrpctl/eigrpctl.8 b/usr.sbin/eigrpctl/eigrpctl.8
new file mode 100644
index 00000000000..032d88a6b6c
--- /dev/null
+++ b/usr.sbin/eigrpctl/eigrpctl.8
@@ -0,0 +1,142 @@
+.\" $OpenBSD: eigrpctl.8,v 1.1 2015/10/02 04:31:52 renato Exp $
+.\"
+.\" Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+.\" Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: October 2 2015 $
+.Dt EIGRPCTL 8
+.Os
+.Sh NAME
+.Nm eigrpctl
+.Nd control the Enhanced Interior Gateway Routing Protocol daemon
+.Sh SYNOPSIS
+.Nm
+.Ar command
+.Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+program controls the
+.Xr eigrpd 8
+daemon.
+Commands may be abbreviated to the minimum unambiguous prefix; for example,
+.Cm s i
+for
+.Cm show interfaces .
+.Pp
+The following commands are available:
+.Bl -tag -width Ds
+.It Cm fib couple
+Insert the learned routes into the Forwarding Information Base
+a.k.a. the kernel routing table.
+.It Cm fib decouple
+Remove the learned routes from the Forwarding Information Base
+a.k.a. the kernel routing table.
+Decoupling the FIB from an EIGRP router may create routing loops and could cause
+major routing issues in the complete EIGRP cloud.
+Only routers with just one link to the EIGRP cloud can safely decouple the FIB.
+.It Cm log brief
+Disable verbose debug logging.
+.It Cm log verbose
+Enable verbose debug logging.
+.It Cm reload
+Reload the configuration file.
+.It Xo
+.Cm show fib
+.Op Cm family Ar family
+.Op Ar filter
+.Xc
+Show the Forwarding Information Base.
+.Ar family ,
+if given, limit the output to the given address family.
+.Ar filter
+can be any of the following:
+.Pp
+.Bl -tag -width "interfaceXXinterfaceXX" -compact
+.It Cm connected
+Show only connected routes.
+.It Cm interface Op Ar interface
+Show only interfaces or the specified
+.Ar interface .
+.It Cm eigrp
+Show only EIGRP routes.
+.It Cm static
+Show only static routes.
+.El
+.Pp
+.Cm connected ,
+.Cm eigrp
+and
+.Cm static
+may be specified together.
+.It Xo
+.Cm show interfaces
+.Op Cm family Ar family
+.Op Cm as Ar as
+.Op Ar interface
+.Xc
+Show details for all EIGRP enabled interfaces or the specified
+.Ar interface .
+.Ar family
+and
+.Ar as ,
+if given, limit the output to the given address family and/or autonomous system.
+.It Xo
+.Cm show neighbor
+.Op Cm family Ar family
+.Op Cm as Ar as
+.Xc
+Show neighbors.
+.Ar family
+and
+.Ar as ,
+if given, limit the output to the given address family and/or autonomous system.
+.It Xo
+.Cm show topology
+.Op Cm family Ar family
+.Op Cm as Ar as
+.Op Ar prefix | filter
+.Xc
+Show the topology table.
+.Ar family
+and
+.Ar as ,
+if given, limit the output to the given address family and/or autonomous system.
+.Ar prefix
+can be specified to show the entries matching a destination prefix.
+.Ar filter
+can be any of the following:
+.Pp
+.Bl -tag -width "interfaceXXinterfaceXX" -compact
+.It Cm active
+Show only active entries.
+.It Cm all-links
+Show all entries.
+.El
+.Sh FILES
+.Bl -tag -width "/var/run/eigrpd.sockXX" -compact
+.It Pa /var/run/eigrpd.sock
+.Ux Ns -domain
+socket used for communication with
+.Xr eigrpd 8 .
+.El
+.Sh SEE ALSO
+.Xr eigrpd.conf 5 ,
+.Xr eigrpd 8
+.Sh HISTORY
+The
+.Nm
+program first appeared in
+.Ox 5.8 .
diff --git a/usr.sbin/eigrpctl/eigrpctl.c b/usr.sbin/eigrpctl/eigrpctl.c
new file mode 100644
index 00000000000..1810dbd1047
--- /dev/null
+++ b/usr.sbin/eigrpctl/eigrpctl.c
@@ -0,0 +1,782 @@
+/* $OpenBSD: eigrpctl.c,v 1.1 2015/10/02 04:31:52 renato Exp $ */
+
+/*
+ * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "eigrp.h"
+#include "eigrpd.h"
+#include "eigrpe.h"
+#include "rde.h"
+#include "log.h"
+#include "parser.h"
+
+__dead void usage(void);
+uint64_t get_ifms_type(uint8_t);
+int show_interface_msg(struct imsg *, struct parse_result *);
+int show_interface_detail_msg(struct imsg *,
+ struct parse_result *);
+const char *print_link(int);
+const char *fmt_timeframe_core(time_t);
+int show_nbr_msg(struct imsg *, struct parse_result *);
+int show_topology_msg(struct imsg *, struct parse_result *);
+int show_topology_detail_msg(struct imsg *,
+ struct parse_result *);
+void show_fib_head(void);
+int show_fib_msg(struct imsg *, struct parse_result *);
+void show_interface_head(void);
+const char * get_media_descr(uint64_t);
+const char * get_linkstate(uint8_t, int);
+void print_baudrate(uint64_t);
+int show_fib_interface_msg(struct imsg *);
+
+struct imsgbuf *ibuf;
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_un sun;
+ struct parse_result *res;
+ struct imsg imsg;
+ unsigned int ifidx = 0;
+ int ctl_sock;
+ int done = 0;
+ int n, verbose = 0;
+ struct ctl_show_topology_req treq;
+
+ /* parse options */
+ if ((res = parse(argc - 1, argv + 1)) == NULL)
+ exit(1);
+
+ /* connect to eigrpd control socket */
+ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ err(1, "socket");
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strlcpy(sun.sun_path, EIGRPD_SOCKET, sizeof(sun.sun_path));
+ if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+ err(1, "connect: %s", EIGRPD_SOCKET);
+
+ if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
+ err(1, NULL);
+ imsg_init(ibuf, ctl_sock);
+ done = 0;
+
+ /* process user request */
+ switch (res->action) {
+ case NONE:
+ usage();
+ /* not reached */
+ case SHOW:
+ case SHOW_IFACE:
+ printf("%-4s %-5s %-11s %-18s %-10s %-8s %3s\n",
+ "AF", "AS", "Interface", "Address", "Linkstate",
+ "Uptime", "nc");
+ /*FALLTHROUGH*/
+ case SHOW_IFACE_DTAIL:
+ if (*res->ifname) {
+ ifidx = if_nametoindex(res->ifname);
+ if (ifidx == 0)
+ errx(1, "no such interface %s", res->ifname);
+ }
+ imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
+ &ifidx, sizeof(ifidx));
+ break;
+ case SHOW_NBR:
+ printf("%-4s %-5s %-18s %-11s %-10s %8s\n", "AF", "AS",
+ "Address", "Iface", "Holdtime", "Uptime");
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
+ break;
+ case SHOW_TOPOLOGY:
+ memset(&treq, 0, sizeof(treq));
+ treq.af = res->family;
+ memcpy(&treq.prefix, &res->addr, sizeof(res->addr));
+ treq.prefixlen = res->prefixlen;
+ treq.flags = res->flags;
+
+ if (!eigrp_addrisset(res->family, &res->addr))
+ printf(" %-4s %-5s %-18s %-15s %-12s %s\n",
+ "AF", "AS", "Destination", "Nexthop", "Interface",
+ "Distance");
+ imsg_compose(ibuf, IMSG_CTL_SHOW_TOPOLOGY, 0, 0, -1,
+ &treq, sizeof(treq));
+ break;
+ case SHOW_FIB:
+ show_fib_head();
+ imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
+ &res->flags, sizeof(res->flags));
+ break;
+ case SHOW_FIB_IFACE:
+ if (*res->ifname)
+ imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
+ res->ifname, sizeof(res->ifname));
+ else
+ imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
+ show_interface_head();
+ break;
+ case FIB:
+ errx(1, "fib couple|decouple");
+ break;
+ case FIB_COUPLE:
+ imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
+ printf("couple request sent.\n");
+ done = 1;
+ break;
+ case FIB_DECOUPLE:
+ imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
+ printf("decouple request sent.\n");
+ done = 1;
+ break;
+ case LOG_VERBOSE:
+ verbose = 1;
+ /* FALLTHROUGH */
+ case LOG_BRIEF:
+ imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
+ &verbose, sizeof(verbose));
+ printf("logging request sent.\n");
+ done = 1;
+ break;
+ case RELOAD:
+ imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
+ printf("reload request sent.\n");
+ done = 1;
+ break;
+ }
+
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
+ err(1, "write error");
+
+ while (!done) {
+ if ((n = imsg_read(ibuf)) == -1)
+ errx(1, "imsg_read error");
+ if (n == 0)
+ errx(1, "pipe closed");
+
+ while (!done) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ errx(1, "imsg_get error");
+ if (n == 0)
+ break;
+ switch (res->action) {
+ case SHOW:
+ case SHOW_IFACE:
+ done = show_interface_msg(&imsg, res);
+ break;
+ case SHOW_IFACE_DTAIL:
+ done = show_interface_detail_msg(&imsg, res);
+ break;
+ case SHOW_NBR:
+ done = show_nbr_msg(&imsg, res);
+ break;
+ case SHOW_TOPOLOGY:
+ if (eigrp_addrisset(res->family, &res->addr))
+ done = show_topology_detail_msg(&imsg,
+ res);
+ else
+ done = show_topology_msg(&imsg, res);
+ break;
+ case SHOW_FIB:
+ done = show_fib_msg(&imsg, res);
+ break;
+ case SHOW_FIB_IFACE:
+ done = show_fib_interface_msg(&imsg);
+ break;
+ case NONE:
+ case FIB:
+ case FIB_COUPLE:
+ case FIB_DECOUPLE:
+ case LOG_VERBOSE:
+ case LOG_BRIEF:
+ case RELOAD:
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ }
+ close(ctl_sock);
+ free(ibuf);
+
+ return (0);
+}
+
+uint64_t
+get_ifms_type(uint8_t if_type)
+{
+ switch (if_type) {
+ case IFT_ETHER:
+ return (IFM_ETHER);
+ case IFT_FDDI:
+ return (IFM_FDDI);
+ case IFT_CARP:
+ return (IFM_CARP);
+ case IFT_PPP:
+ return (IFM_TDM);
+ default:
+ return (0);
+ }
+}
+
+int
+show_interface_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct ctl_iface *iface;
+ char *addr;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_INTERFACE:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE +
+ sizeof(struct ctl_iface))
+ errx(1, "wrong imsg len");
+ iface = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != iface->af)
+ break;
+ if (res->as != 0 && res->as != iface->as)
+ break;
+
+ if (asprintf(&addr, "%s/%d", log_addr(iface->af, &iface->addr),
+ iface->prefixlen) == -1)
+ err(1, NULL);
+
+ printf("%-4s %-5u %-11s %-18s", af_name(iface->af), iface->as,
+ iface->name, addr);
+ if (strlen(addr) > 18)
+ printf("\n%41s", " ");
+ printf(" %-10s %-8s %3u\n", get_linkstate(iface->if_type,
+ iface->linkstate), fmt_timeframe_core(iface->uptime),
+ iface->nbr_cnt);
+ free(addr);
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+show_interface_detail_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct ctl_iface *iface;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_INTERFACE:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE +
+ sizeof(struct ctl_iface))
+ errx(1, "wrong imsg len");
+ iface = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != iface->af)
+ break;
+ if (res->as != 0 && res->as != iface->as)
+ break;
+
+ printf("\n");
+ printf("Interface %s, line protocol is %s\n",
+ iface->name, print_link(iface->flags));
+ printf(" Autonomous System %u, Address Family %s\n",
+ iface->as, af_name(iface->af));
+ printf(" Internet address %s/%d\n",
+ log_addr(iface->af, &iface->addr), iface->prefixlen);
+ printf(" Linkstate %s, network type %s\n",
+ get_linkstate(iface->if_type, iface->linkstate),
+ if_type_name(iface->type));
+ printf(" Delay %u usec, Bandwidth %u Kbit/sec\n",
+ iface->delay, iface->bandwidth);
+ if (iface->passive)
+ printf(" Passive interface (No Hellos)\n");
+ else {
+ printf(" Hello interval %u, Hello holdtime %u\n",
+ iface->hello_interval, iface->hello_holdtime);
+ printf(" Split-horizon %s\n",
+ (iface->splithorizon) ? "enabled" : "disabled");
+ printf(" Neighbor count is %d\n", iface->nbr_cnt);
+ }
+ printf(" Uptime %s\n", fmt_timeframe_core(iface->uptime));
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+const char *
+print_link(int state)
+{
+ if (state & IFF_UP)
+ return ("UP");
+ else
+ return ("DOWN");
+}
+
+#define TF_BUFS 8
+#define TF_LEN 9
+
+const char *
+fmt_timeframe_core(time_t t)
+{
+ char *buf;
+ static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
+ static int idx = 0;
+ unsigned int sec, min, hrs, day;
+ unsigned long long week;
+
+ if (t == 0)
+ return ("00:00:00");
+
+ buf = tfbuf[idx++];
+ if (idx == TF_BUFS)
+ idx = 0;
+
+ week = t;
+
+ sec = week % 60;
+ week /= 60;
+ min = week % 60;
+ week /= 60;
+ hrs = week % 24;
+ week /= 24;
+ day = week % 7;
+ week /= 7;
+
+ if (week > 0)
+ snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
+ else if (day > 0)
+ snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
+ else
+ snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
+
+ return (buf);
+}
+
+int
+show_nbr_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct ctl_nbr *nbr;
+ const char *addr;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_NBR:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_nbr))
+ errx(1, "wrong imsg len");
+ nbr = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != nbr->af)
+ break;
+ if (res->as != 0 && res->as != nbr->as)
+ break;
+
+ addr = log_addr(nbr->af, &nbr->addr);
+
+ printf("%-4s %-5u %-18s", af_name(nbr->af), nbr->as, addr);
+ if (strlen(addr) > 18)
+ printf("\n%29s", " ");
+ printf(" %-11s %-10u %8s\n", nbr->ifname, nbr->hello_holdtime,
+ fmt_timeframe_core(nbr->uptime));
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static int
+connected_check(int af, union eigrpd_addr *addr)
+{
+ switch (af) {
+ case AF_INET:
+ if (addr->v4.s_addr == INADDR_ANY)
+ return (1);
+ break;
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
+ return (1);
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+show_topology_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct ctl_rt *rt;
+ char *dstnet, *nexthop, *rdistance;
+ char flag;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_TOPOLOGY:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt))
+ errx(1, "wrong imsg len");
+ rt = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != rt->af)
+ break;
+ if (res->as != 0 && res->as != rt->as)
+ break;
+
+ if (rt->state & DUAL_STA_ACTIVE_ALL)
+ flag = 'A';
+ else if (rt->flags & F_CTL_RT_SUCCESSOR)
+ flag = 'S';
+ else if (rt->flags & F_CTL_RT_FSUCCESSOR)
+ flag = 'F';
+ else
+ flag = ' ';
+
+ if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, &rt->prefix),
+ rt->prefixlen) == -1)
+ err(1, NULL);
+
+ if (connected_check(rt->af, &rt->nexthop)) {
+ if (asprintf(&nexthop, "Connected") == -1)
+ err(1, NULL);
+ if (asprintf(&rdistance, "-") == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&nexthop, "%s", log_addr(rt->af,
+ &rt->nexthop)) == -1)
+ err(1, NULL);
+ if (asprintf(&rdistance, "%u", rt->rdistance) == -1)
+ err(1, NULL);
+ }
+
+ printf("%c %-4s %-5u %-18s", flag, af_name(rt->af), rt->as,
+ dstnet);
+ if (strlen(dstnet) > 18)
+ printf("\n%31s", " ");
+ printf(" %-15s", nexthop);
+ if (strlen(nexthop) > 15)
+ printf("\n%47s", " ");
+ printf(" %-12s %u/%s\n", rt->ifname, rt->distance, rdistance);
+ free(dstnet);
+ free(nexthop);
+ free(rdistance);
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+show_topology_detail_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct ctl_rt *rt;
+ char *dstnet = NULL, *state = NULL, *type, *nexthop;
+ struct in_addr addr;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_TOPOLOGY:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt))
+ errx(1, "wrong imsg len");
+ rt = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != rt->af)
+ break;
+ if (res->as != 0 && res->as != rt->as)
+ break;
+
+ if (rt->flags & F_CTL_RT_FIRST) {
+ if (asprintf(&dstnet, "%s/%d", log_addr(rt->af,
+ &rt->prefix), rt->prefixlen) == -1)
+ err(1, NULL);
+
+ if (rt->state & DUAL_STA_ACTIVE_ALL) {
+ if (asprintf(&state, "Active") == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&state, "Passive") == -1)
+ err(1, NULL);
+ }
+ }
+
+ if (rt->type == EIGRP_ROUTE_INTERNAL) {
+ if (asprintf(&type, "Internal") == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&type, "External") == -1)
+ err(1, NULL);
+ }
+
+ if (connected_check(rt->af, &rt->nexthop)) {
+ if (asprintf(&nexthop, "Connected") == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&nexthop, "Neighbor %s", log_addr(rt->af,
+ &rt->nexthop)) == -1)
+ err(1, NULL);
+ }
+
+ if (rt->flags & F_CTL_RT_FIRST) {
+ printf("Network %s\n", dstnet);
+ printf("Autonomous System %u, Address Family %s\n",
+ rt->as, af_name(rt->af));
+ printf("DUAL State: %s, Feasible Distance: %u\n", state,
+ rt->fdistance);
+ printf("Routes:\n");
+ }
+ printf(" Interface %s - %s\n", rt->ifname, nexthop);
+ printf(" Distance: %u", rt->distance);
+ if (!connected_check(rt->af, &rt->nexthop))
+ printf(", Reported Distance: %u", rt->rdistance);
+ printf(", route is %s\n", type);
+ printf(" Vector metric:\n");
+ printf(" Minimum bandwidth is %u Kbit\n",
+ rt->metric.bandwidth);
+ printf(" Total delay is %u microseconds\n",
+ rt->metric.delay);
+ printf(" Reliability is %u/255\n", rt->metric.reliability);
+ printf(" Load is %u/255\n", rt->metric.load);
+ printf(" Minimum MTU is %u\n", rt->metric.mtu);
+ printf(" Hop count is %u\n", rt->metric.hop_count);
+ if (rt->type == EIGRP_ROUTE_EXTERNAL) {
+ addr.s_addr = htonl(rt->emetric.routerid);
+ printf(" External data:\n");
+ printf(" Originating router is %s\n",
+ inet_ntoa(addr));
+ printf(" AS number of route is %u\n",
+ rt->emetric.as);
+ printf(" External protocol is %s\n",
+ ext_proto_name(rt->emetric.protocol));
+ printf(" External metric is %u\n",
+ rt->emetric.metric);
+ printf(" Administrator tag is %u\n",
+ rt->emetric.tag);
+ }
+
+ printf("\n");
+ if (dstnet)
+ free(dstnet);
+ if (state)
+ free(state);
+ free(type);
+ free(nexthop);
+ break;
+ case IMSG_CTL_END:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+void
+show_fib_head(void)
+{
+ printf("flags: * = valid, D = EIGRP, C = Connected, S = Static\n");
+ printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio", "Destination",
+ "Nexthop");
+}
+
+int
+show_fib_msg(struct imsg *imsg, struct parse_result *res)
+{
+ struct kroute *k;
+ char *p;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_KROUTE:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
+ errx(1, "wrong imsg len");
+ k = imsg->data;
+
+ if (res->family != AF_UNSPEC && res->family != k->af)
+ break;
+
+ if (k->flags & F_DOWN)
+ printf(" ");
+ else
+ printf("*");
+
+ if (!(k->flags & F_KERNEL))
+ printf("D");
+ else if (k->flags & F_CONNECTED)
+ printf("C");
+ else if (k->flags & F_STATIC)
+ printf("S");
+ else
+ printf(" ");
+
+ printf("%-5s", (k->flags & F_CTL_EXTERNAL) ? " EX" : "");
+ printf("%4d ", k->priority);
+ if (asprintf(&p, "%s/%u", log_addr(k->af, &k->prefix),
+ k->prefixlen) == -1)
+ err(1, NULL);
+ printf("%-20s ", p);
+ if (strlen(p) > 20)
+ printf("\n%33s", " ");
+ free(p);
+
+ if (eigrp_addrisset(k->af, &k->nexthop)) {
+ switch (k->af) {
+ case AF_INET:
+ printf("%s", log_addr(k->af, &k->nexthop));
+ break;
+ case AF_INET6:
+ printf("%s", log_in6addr_scope(&k->nexthop.v6,
+ k->ifindex));
+ break;
+ default:
+ break;
+ }
+
+ } else if (k->flags & F_CONNECTED)
+ printf("link#%u", k->ifindex);
+ printf("\n");
+
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+void
+show_interface_head(void)
+{
+ printf("%-15s%-15s%s\n", "Interface", "Flags",
+ "Link state");
+}
+
+const struct if_status_description
+ if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
+const struct ifmedia_description
+ ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
+
+const char *
+get_media_descr(uint64_t media_type)
+{
+ const struct ifmedia_description *p;
+
+ for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
+ if (media_type == p->ifmt_word)
+ return (p->ifmt_string);
+
+ return ("unknown");
+}
+
+const char *
+get_linkstate(uint8_t if_type, int link_state)
+{
+ const struct if_status_description *p;
+ static char buf[8];
+
+ for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
+ if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
+ return (p->ifs_string);
+ }
+ snprintf(buf, sizeof(buf), "[#%d]", link_state);
+ return (buf);
+}
+
+void
+print_baudrate(uint64_t baudrate)
+{
+ if (baudrate > IF_Gbps(1))
+ printf("%llu GBit/s", baudrate / IF_Gbps(1));
+ else if (baudrate > IF_Mbps(1))
+ printf("%llu MBit/s", baudrate / IF_Mbps(1));
+ else if (baudrate > IF_Kbps(1))
+ printf("%llu KBit/s", baudrate / IF_Kbps(1));
+ else
+ printf("%llu Bit/s", baudrate);
+}
+
+int
+show_fib_interface_msg(struct imsg *imsg)
+{
+ struct kif *k;
+ uint64_t ifms_type;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_IFINFO:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kif))
+ errx(1, "wrong imsg len");
+ k = imsg->data;
+ printf("%-15s", k->ifname);
+ printf("%-15s", k->flags & IFF_UP ? "UP" : "");
+ ifms_type = get_ifms_type(k->if_type);
+ if (ifms_type)
+ printf("%s, ", get_media_descr(ifms_type));
+
+ printf("%s", get_linkstate(k->if_type, k->link_state));
+
+ if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
+ printf(", ");
+ print_baudrate(k->baudrate);
+ }
+ printf("\n");
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/eigrpctl/parser.c b/usr.sbin/eigrpctl/parser.c
new file mode 100644
index 00000000000..ec940790272
--- /dev/null
+++ b/usr.sbin/eigrpctl/parser.c
@@ -0,0 +1,454 @@
+/* $OpenBSD: parser.c,v 1.1 2015/10/02 04:31:52 renato Exp $ */
+
+/*
+ * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "eigrpd.h"
+
+#include "parser.h"
+
+enum token_type {
+ NOTOKEN,
+ ENDTOKEN,
+ KEYWORD,
+ FAMILY,
+ ASNUM,
+ ADDRESS,
+ FLAG,
+ PREFIX,
+ IFNAME
+};
+
+struct token {
+ enum token_type type;
+ const char *keyword;
+ int value;
+ const struct token *next;
+};
+
+static const struct token t_main[];
+static const struct token t_fib[];
+static const struct token t_show[];
+static const struct token t_show_iface[];
+static const struct token t_show_iface_af[];
+static const struct token t_show_iface_as[];
+static const struct token t_show_nbr[];
+static const struct token t_show_nbr_af[];
+static const struct token t_show_nbr_as[];
+static const struct token t_show_topology[];
+static const struct token t_show_topology_af[];
+static const struct token t_show_topology_as[];
+static const struct token t_show_fib[];
+static const struct token t_show_fib_af[];
+static const struct token t_log[];
+
+static const struct token t_main[] = {
+ {KEYWORD, "reload", RELOAD, NULL},
+ {KEYWORD, "fib", FIB, t_fib},
+ {KEYWORD, "show", SHOW, t_show},
+ {KEYWORD, "log", NONE, t_log},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_fib[] = {
+ { KEYWORD, "couple", FIB_COUPLE, NULL},
+ { KEYWORD, "decouple", FIB_DECOUPLE, NULL},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface},
+ {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr},
+ {KEYWORD, "topology", SHOW_TOPOLOGY, t_show_topology},
+ {KEYWORD, "fib", SHOW_FIB, t_show_fib},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_iface[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "family", NONE, t_show_iface_af},
+ {KEYWORD, "as", NONE, t_show_iface_as},
+ {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL},
+ {IFNAME, "", SHOW_IFACE_DTAIL, NULL},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_iface_af[] = {
+ {FAMILY, "", NONE, t_show_iface},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_iface_as[] = {
+ {ASNUM, "", NONE, t_show_iface},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_nbr[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "family", NONE, t_show_nbr_af},
+ {KEYWORD, "as", NONE, t_show_nbr_as},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_nbr_af[] = {
+ {FAMILY, "", NONE, t_show_nbr},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_nbr_as[] = {
+ {ASNUM, "", NONE, t_show_nbr},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_topology[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "family", NONE, t_show_topology_af},
+ {KEYWORD, "as", NONE, t_show_topology_as},
+ {PREFIX, "", NONE, NULL},
+ {FLAG, "active", F_CTL_ACTIVE, NONE},
+ {FLAG, "all-links", F_CTL_ALLLINKS, NONE},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_topology_af[] = {
+ {FAMILY, "", NONE, t_show_topology},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_topology_as[] = {
+ {ASNUM, "", NONE, t_show_topology},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_fib[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "family", NONE, t_show_fib_af},
+ {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface},
+ {FLAG, "connected", F_CONNECTED, t_show_fib},
+ {FLAG, "static", F_STATIC, t_show_fib},
+ {FLAG, "eigrp", F_EIGRPD_INSERTED, t_show_fib},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_fib_af[] = {
+ {FAMILY, "", NONE, t_show_fib},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_log[] = {
+ {KEYWORD, "verbose", LOG_VERBOSE, NULL},
+ {KEYWORD, "brief", LOG_BRIEF, NULL},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token *match_token(const char *, const struct token *,
+ struct parse_result *);
+static void show_valid_args(const struct token *);
+
+struct parse_result *
+parse(int argc, char *argv[])
+{
+ static struct parse_result res;
+ const struct token *table = t_main;
+ const struct token *match;
+
+ memset(&res, 0, sizeof(res));
+
+ while (argc >= 0) {
+ if ((match = match_token(argv[0], table, &res)) == NULL) {
+ fprintf(stderr, "valid commands/args:\n");
+ show_valid_args(table);
+ return (NULL);
+ }
+
+ argc--;
+ argv++;
+
+ if (match->type == NOTOKEN || match->next == NULL)
+ break;
+
+ table = match->next;
+ }
+
+ if (argc > 0) {
+ fprintf(stderr, "superfluous argument: %s\n", argv[0]);
+ return (NULL);
+ }
+
+ return (&res);
+}
+
+static const struct token *
+match_token(const char *word, const struct token *table,
+ struct parse_result *res)
+{
+ unsigned int i, match;
+ const struct token *t = NULL;
+
+ match = 0;
+
+ for (i = 0; table[i].type != ENDTOKEN; i++) {
+ switch (table[i].type) {
+ case NOTOKEN:
+ if (word == NULL || strlen(word) == 0) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case KEYWORD:
+ if (word != NULL && strncmp(word, table[i].keyword,
+ strlen(word)) == 0) {
+ match++;
+ t = &table[i];
+ if (t->value)
+ res->action = t->value;
+ }
+ break;
+ case FLAG:
+ if (word != NULL && strncmp(word, table[i].keyword,
+ strlen(word)) == 0) {
+ match++;
+ t = &table[i];
+ res->flags |= t->value;
+ }
+ break;
+ case FAMILY:
+ if (word == NULL)
+ break;
+ if (!strcmp(word, "inet") ||
+ !strcasecmp(word, "IPv4")) {
+ match++;
+ t = &table[i];
+ res->family = AF_INET;
+ }
+ if (!strcmp(word, "inet6") ||
+ !strcasecmp(word, "IPv6")) {
+ match++;
+ t = &table[i];
+ res->family = AF_INET6;
+ }
+ break;
+ case ASNUM:
+ if (parse_asnum(word, &res->as)) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case ADDRESS:
+ if (parse_addr(word, &res->family, &res->addr)) {
+ match++;
+ t = &table[i];
+ if (t->value)
+ res->action = t->value;
+ }
+ break;
+ case PREFIX:
+ if (parse_prefix(word, &res->family, &res->addr,
+ &res->prefixlen)) {
+ match++;
+ t = &table[i];
+ if (t->value)
+ res->action = t->value;
+ }
+ break;
+ case IFNAME:
+ if (!match && word != NULL && strlen(word) > 0) {
+ if (strlcpy(res->ifname, word,
+ sizeof(res->ifname)) >=
+ sizeof(res->ifname))
+ err(1, "interface name too long");
+ match++;
+ t = &table[i];
+ if (t->value)
+ res->action = t->value;
+ }
+ break;
+
+ case ENDTOKEN:
+ break;
+ }
+ }
+
+ if (match != 1) {
+ if (word == NULL)
+ fprintf(stderr, "missing argument:\n");
+ else if (match > 1)
+ fprintf(stderr, "ambiguous argument: %s\n", word);
+ else if (match < 1)
+ fprintf(stderr, "unknown argument: %s\n", word);
+ return (NULL);
+ }
+
+ return (t);
+}
+
+static void
+show_valid_args(const struct token *table)
+{
+ int i;
+
+ for (i = 0; table[i].type != ENDTOKEN; i++) {
+ switch (table[i].type) {
+ case NOTOKEN:
+ fprintf(stderr, " <cr>\n");
+ break;
+ case KEYWORD:
+ case FLAG:
+ fprintf(stderr, " %s\n", table[i].keyword);
+ break;
+ case FAMILY:
+ fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n");
+ break;
+ case ASNUM:
+ fprintf(stderr, " <asnum>\n");
+ break;
+ case ADDRESS:
+ fprintf(stderr, " <address>\n");
+ break;
+ case PREFIX:
+ fprintf(stderr, " <address>[/<len>]\n");
+ break;
+ case IFNAME:
+ fprintf(stderr, " <interface>\n");
+ break;
+ case ENDTOKEN:
+ break;
+ }
+ }
+}
+
+int
+parse_asnum(const char *word, uint16_t *asnum)
+{
+ const char *errstr;
+ uint32_t uval;
+
+ if (word == NULL)
+ return (0);
+
+ uval = strtonum(word, EIGRP_MIN_AS, EIGRP_MAX_AS, &errstr);
+ if (errstr)
+ errx(1, "AS number is %s: %s", errstr, word);
+
+ *asnum = uval;
+ return (1);
+}
+
+int
+parse_addr(const char *word, int *family, union eigrpd_addr *addr)
+{
+ struct in_addr ina;
+ struct addrinfo hints, *r;
+ struct sockaddr_in6 *sa_in6;
+
+ if (word == NULL)
+ return (0);
+
+ memset(addr, 0, sizeof(union eigrpd_addr));
+ memset(&ina, 0, sizeof(ina));
+
+ if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
+ *family = AF_INET;
+ addr->v4.s_addr = ina.s_addr;
+ return (1);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(word, "0", &hints, &r) == 0) {
+ sa_in6 = (struct sockaddr_in6 *)r->ai_addr;
+ *family = AF_INET6;
+ addr->v6 = sa_in6->sin6_addr;
+ freeaddrinfo(r);
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+parse_prefix(const char *word, int *family, union eigrpd_addr *addr,
+ uint8_t *prefixlen)
+{
+ char *p, *ps;
+ const char *errstr;
+ size_t wordlen;
+ int mask = -1;
+
+ if (word == NULL)
+ return (0);
+ wordlen = strlen(word);
+
+ memset(addr, 0, sizeof(union eigrpd_addr));
+
+ if ((p = strrchr(word, '/')) != NULL) {
+ size_t plen = strlen(p);
+ mask = strtonum(p + 1, 0, 128, &errstr);
+ if (errstr)
+ errx(1, "netmask %s", errstr);
+
+ if ((ps = malloc(wordlen - plen + 1)) == NULL)
+ err(1, "parse_prefix: malloc");
+ strlcpy(ps, word, wordlen - plen + 1);
+
+ if (parse_addr(ps, family, addr) == 0) {
+ free(ps);
+ return (0);
+ }
+
+ free(ps);
+ } else
+ if (parse_addr(word, family, addr) == 0)
+ return (0);
+
+ switch (*family) {
+ case AF_INET:
+ if (mask == UINT8_MAX)
+ mask = 32;
+ if (mask > 32)
+ errx(1, "invalid netmask: too large");
+ break;
+ case AF_INET6:
+ if (mask == UINT8_MAX)
+ mask = 128;
+ if (mask > 128)
+ errx(1, "invalid netmask: too large");
+ break;
+ default:
+ return (0);
+ }
+ eigrp_applymask(*family, addr, addr, mask);
+ *prefixlen = mask;
+
+ return (1);
+}
diff --git a/usr.sbin/eigrpctl/parser.h b/usr.sbin/eigrpctl/parser.h
new file mode 100644
index 00000000000..3c44b005a1f
--- /dev/null
+++ b/usr.sbin/eigrpctl/parser.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: parser.h,v 1.1 2015/10/02 04:31:52 renato Exp $ */
+
+/*
+ * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PARSER_H_
+#define _PARSER_H_
+
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+enum actions {
+ NONE,
+ FIB,
+ FIB_COUPLE,
+ FIB_DECOUPLE,
+ LOG_VERBOSE,
+ LOG_BRIEF,
+ SHOW,
+ SHOW_IFACE,
+ SHOW_IFACE_DTAIL,
+ SHOW_NBR,
+ SHOW_TOPOLOGY,
+ SHOW_FIB,
+ SHOW_FIB_IFACE,
+ RELOAD
+};
+
+struct parse_result {
+ int family;
+ uint16_t as;
+ union eigrpd_addr addr;
+ uint8_t prefixlen;
+ char ifname[IF_NAMESIZE];
+ int flags;
+ enum actions action;
+};
+
+struct parse_result *parse(int, char *[]);
+int parse_asnum(const char *, uint16_t *);
+int parse_addr(const char *, int *,
+ union eigrpd_addr *);
+int parse_prefix(const char *, int *,
+ union eigrpd_addr *, uint8_t *);
+
+#endif /* _PARSER_H_ */